Linux-编程基础

编程基础

GCC程序编译

文件类型

.c:C语言源代码文件

.a:由目标文件构成的库文件

.C .cc .cxx:C++源代码文件

.h:头文件

.i:已经预处理过的C源代码文件

.ii:已经预处理过的C++源代码文件

.o:编译后的目标文件

.s:汇编语言源代码文件

.S:经过预编译的汇编语言源代码文件

例:

hello.c

#include 
int main(void)
{
    printf("Hello world\n");
    return 0;
}

编译和运行这段程序:

gcc hello.c -o hello
./hello

输出:

Hello world

基本用法

gcc最基本的用法是:

gcc [options] [filename]

options:编译器所需要的编译选项

filenames:要编译的文件名

编译选项

最基本最常用的参数

-o output_filename:确定可执行文件的名称为output_filename。如果不给出这个选项,gcc就给出预设的可执行文件a.out

-c:只编译,不连接成为可执行文件,编译器只是由输入的.c等源文件生成.o为后缀的目标文件。

-g:产生调试工具(GNU的gdb)所必要的符号信息,要想对编译出的程序进行调试,就必须加入这个选项。

-O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应的要慢一些

-O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。

例程:

#include 
int main(void)
{
 double counter;
 double result;
 double temp;
 for(counter = 0; counter < 2000.0 * 2000.0 * 2000.0 / 20 + 2020; counter += (5-1)/4)
 {
 temp = counter / 1979;
 result = counter;
 }
 printf("Result is %lf\n", result);
 return 0;
}
gcc optimize.c -o optimize
time ./optimize

real 0m1.300s
user 0m1.300s
sys 0m0.000s

gcc -O optimize.c -o optimize
time ./optimize

real 0m0.555s
user 0m0.555s
sys  0m0.000s

对比看出程序的性能的确得到很大的改善

-Idirname:将dirname所指出的目录加入到程序头文件目录列表中

C程序中的头文件包含两种情况:

#include 
#include "B.h"

对于<>,预处理器程序cpp在系统预设的头文件目录(如/user/include)中搜索相应的文件;而对于"",cpp在当前目录中搜索头文件。这个选项的作用是告诉cpp,如果在当前目录中没有找到需要的文件,就到指定的dirname目录中去寻找

例:

gcc foo.c -I/home/include -o foo

标准的头文件路径在: /user/include

注意是大写i

-Ldirname:将dirname所指出的目录加入到库文件的目录列表中。在默认状态下,连接程序ld在系统得预设路径中(如/usr/lib)寻找所需要的库文件,这个选项告诉连接程序,首先到-L指定的目录中去寻找,然后到系统预设路径中寻找。

主要是用到动态链接库, 一般的动态链接库在/usr/lib下面,如果自己写的库也想使用,就需要把自己的库的路径添加到gcc标准寻找库的路径中去

-lname:在连接时,装载名字为“libname.a”的函数库,该函数库位于系统预设的目录或者由-L选项确定的目录下。例如,-lm表示连接名为“libm.a”的数学函数库。

gcc foo.c -L/home/lib -lfoo -o foo

-static:静态链接库文件

例:

gcc -static hello.c -o hello

库由动态和静态两种,动态通常用.so为后缀,静态用.a为后缀。当使用静态库时,连接器找出程序所需的函数,然后将他们拷贝到可执行文件,一旦连接成功,静态程序库也就不再需要了。然而,对动态库而言,就不是这样了,动态库会在执行程序内留下一个标记指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库。

使用动态链接库的时候,动态链接库本身的这些代码并不会进入到程序代码当中,仅仅是一种调用关系,因此可以被多个程序共享,所以又叫做共享库。但静态链接库的代码会进入到我们的程序里面去,我们的程序就会变大,它实际上是把静态链接库的代码拷贝到程序当中去。

演示:静态链接库和动态链接库可执行文件大小比较

gcc -static hello.c -o hello
ll
drwxrwxr-x 3 xiao xiao 4096 8月  21 11:05 ./
drwxrwxr-x 4 xiao xiao 4096 8月  21 09:25 ../
-rwxrwxr-x 1 xiao xiao 8600 8月  21 11:05 hello*
-rw-rw-r-- 1 xiao xiao   76 8月  21 09:24 hello.c

gcc -static hello.c -o hello
ll
drwxrwxr-x 3 xiao xiao   4096 8月  21 11:05 ./

drwxrwxr-x 4 xiao xiao   4096 8月  21 09:25 ../
-rwxrwxr-x 1 xiao xiao 912720 8月  21 11:05 hello*
-rw-rw-r-- 1 xiao xiao     76 8月  21 09:24 hello.c

可以看到生成的hello文件大了很多

-Wall:生成所有警告信息

-w:不生成任何警告信息

-DMACRO:定义MACRO宏,等效于在程序中使用#define MACRO

GDB程序调试

GDB的主要功能:

  • 启动被调试程序

  • 让被调试的程序在指定的位置停住

  • 当程序被停住时,可以检查程序状态

测试:

#include 

int main(void)
{
    int i;
    long result = 0;
    for(i = 1; i <= 100; i++)
    {
        result += i;
    }
    printf("result = %d\n", result);
}
  1. 编译生成可执行文件:

    gcc -g tst.c -o tst
    
  2. 启动GDB

    gdb tst
    
  3. 在main函数处设置断点

    break main
    
  4. 运行程序

    run
    
  5. 单步运行

    next
    
  6. 继续运行

    continue
    

启动GDB

1. gdb 调试程序名
2. gdb
file 调试程序名

GDB命令

list(l) 查看程序

break(b)函数名 在某函数入口处添加断点

break(b)行号 在指定行添加断点

break(b)文件名:行号 在指定文件的指定行添加断点

break(b)行号if条件 当条件为真时,指定行号处断点生效,例

b 5 if i=10

当i等于10时第五行断点生效

info break 查看所有设置的断点

delete 断点编号 删除断点

run(r) 开始运行程序

next(n) 单步运行程序(不进入子函数)

step(s) 单步运行程序(进入子函数)

continue(c) 继续运行程序

print(p) 变量名 查看指定变量值

finish 运行程序,知道当前函数结束

watch 变量名 对指定变量进行监控

quit(q) 退出gdb

Makefile工程管理

make在执行时,需要一个命名为Makefile的文件。Makefile文件描述了整个工程文件的编译,连接等规则。

其中包括:工程中的那些源文件需要编译以及如何编译;需要创建哪些库文件以及如何创建这些库文件、如何最后产生我们想要的可执行文件。

hello:main.o func1.o func2.o
    gcc main.o func1.o func2.o -o hello
main.o:main.c
    gcc -c main.c
func1.o:func1.c
    gcc -c func1.c
func2.o:func2.c
    gcc -c func2.c
.PHONY:clean
clean:
    rm -f hello main.o func1.o func2.o

Makefile术语

规则:用于说明如何生成一个或多个目标文件,规则格式如下:

targets:prerequisties
    command

目标 依赖 命令

main.0:main.c
    gcc -c main.c

命令需要以[TAB]键开始

文件名

make命令默认在当前目录下寻找名字为makefile或者Makefile的工程文件,当名字不为这两者之一时,可以使用如下方法指定:

make -f 文件名

伪目标

Makefile中把那些没有任何依赖只有执行动作的目标称为“伪目标”(phony targets)

.PHONY:clean
clean:
    rm -f hello main.o func1.o func2.o

".PHONY"将“clean”目标声明为伪目标

变量

hello:main.o func1.o func2.o func3.o
    gcc main.o func1.o func2.o func3.o -o hello

等同于
obj=main.o func1.o func2.o func3.o
hello:$(obj)
    gcc $(obj) -o hello

在makefile中,存在系统默认的自动变量

$^:代表所有的依赖文件

$@:代表目标

$<:代表第一个依赖文件

hello:main.o func1.o func2.o
    gcc main.o func1.o func2.o -o hello

hello:main.o func1.o func2.o
    gcc $^ -o $@

杂项

Makefile中“#”字符后的内容被视作解释

hello:hello.c

@gcc hello.c -o hello

@:取消回显

posted @ 2019-09-05 14:59  LOXO  阅读(245)  评论(0编辑  收藏  举报