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);
}
-
编译生成可执行文件:
gcc -g tst.c -o tst
-
启动GDB
gdb tst
-
在main函数处设置断点
break main
-
运行程序
run
-
单步运行
next
-
继续运行
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
@:取消回显