1. gcc编译器
1.1 简介
gcc编译器(GNU compiler)是GNU推出的多平台编译器,可将C,C++源程序编译连接成可执行文件,支持以下后缀 .c :C语言源代码 .h :程序所包含的头文件 .i :已经预处理过的c源代码文件 .s :汇编语言源代码文件 .o :编译后的目标文件 .a .so :编译后的库文件
1.2 编译过程
1、预处理,生成 .i 的文件[预处理器cpp] 2、将预处理后的文件转换成汇编语言, 生成文件 .s [编译器egcs] 3、有汇编变为目标代码(机器代码)生成 .o 的文件[汇编器as] 4、连接目标代码, 生成可执行程序 [链接器ld]
1.3 常用的编译命令选项
常用编译假设源程序文件名为test.c。
- 无选项编译链接
用法:gcc test.c 作用:将test.c预处理、汇编、编译并链接形成可执行文件。这里未指定输出文件,默认输出为a.out。
2. 选项 -o 用法:gcc test.c -o test 作用:将test.c预处理、汇编、编译并链接形成可执行文件test。-o选项用来指定输出文件的文件名。
-
选项 -E 用法:gcc -E test.c -o test.i 作用:将test.c预处理输出test.i文件。 -
选项 -S 用法:gcc -S test.i 作用:将预处理输出文件test.i汇编成test.s文件。 -
选项 -c 用法:gcc -c test.s 作用:将汇编输出文件test.s编译输出test.o文件。 -
无选项链接 用法:gcc test.o -o test 作用:将编译输出文件test.o链接成最终可执行文件test。 -
选项-O 用法:gcc -O1 test.c -o test
3)其他编译方式
1.4 多源文件的编译方法
如果有多个源文件,基本上有两种编译方法: [假设有两个源文件为test.c和testfun.c]
-
多个文件一起编译 用法:gcc testfun.c test.c -o test 作用:将testfun.c和test.c分别编译后链接成test可执行文件。 -
分别编译各个源文件,之后对编译后输出的目标文件链接。
1.5 gcc调试c语言常见错误及对策
- C语法错误
错误信息:文件source.c中第n行有语法错误(syntex error) 解决方法:重新进入文件查看相应的语法 - 头文件错误
错误信息:找不到头文件head.h(can not find include file head.h) 解决方法:查看包含的头文件是否是目录名错误和双引号或者尖括号错误 - 档案库错误
错误信息:链接程序找不到所需的函数库(ld : -lm: no such file or directory) 原因:能存在函数名错误、指定的函数库所在的目录名称错误等。 解决方法:需要使用find命令在目录中查找出相应的函数库名,确定正确的函数名称。 - 未定义符号
错误信息:有未定义的符号(Undefined symbol) 原因: 1.使用者自己定义的函数或者全局变量所在源代码文件没有被编译连接,或者干脆没有定义 2.为定义的符号是一个标准的库函数,在源程序中使用了该库函数,而连接过程中还没有给定相应函数库的名称 解决方法: 对于原因1:需要使用这根据实际情况修改源程序,给出全局变量或者函数的定义体或者干脆没有定义 对于原因2.为定义的符号是一个标准的库函数,在源程序中使用了该库函数,而连接过程中还没有给定相应函数库的名称
举例
假设有两个源文件 main.c 和 factorial.c 两个源文件,现在要编译生成一个计算阶乘的程序。
int factorial (int n)
{
if (n <= 1)
return 1;
else
return factorial (n - 1) * n;
}
int factorial (int n);
int main (int argc, char **argv)
{
int n;
if (argc < 2)
{
printf ("Usage: %s n\n", argv [0]);
return -1;
}
else
{
n = atoi (argv[1]);
printf ("Factorial of %d is %d.\n", n, factorial (n));
}
return 0;
}
利用如下的命令可编译生成可执行文件,并执行程序:
$ gcc -o factorial main.c factorial.c
$ ./factorial 5
Factorial of 5 is 120.
2. gdb调试器
2.1 简介
GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,可完成以下功能:
- 运行被调试程序,设置所有能影响该程序的参数和变量
- 保证被调试程序在指定的条件下停止运行
- 当被调试程序停止时,让开发工程师检查发生了什么
- 根据每次调试器的提示信息来做相应的改变,以便修正某个错误引起的问题
2.2 gdb使用
1.开始调试 首先使用gcc对源文件进行编译,一定要加上-g 显示调试信息,如下
gcc -g test.c
gdb a.out
或者使用-o 对特定的名字的可执行程序进行调试
gcc -g test.c -o test
gdb test
2.gdb调试参数
命令 | 功能 |
---|
(gdb)l | 参看源文件(默认为前10行),加标号,回到第一次显示10行的位置,如l 1。 同理可跳转值l 2 | (gdb)b N | 在N行设置断点 | (gdb)info b | 查看设置断点情况 | (gdb)del n | 删除断点,如删除第一个断点为del 1,同样删除第二个断点为del 2 | (gdb)r | 运行代码 | (gdb)p n | 查看变量值 | (gdb)n | 单步运行,遇到函数不进入 | (gdb)s | 单步运行,遇到函数进入函数 | (gdb)c | 恢复程序运行吗,直接运行到程序的下一个断点 | (gdb)help command | 帮助 | (gdb)q | 退出gdb调试 |
2.3 调试流程
在Linux中使用gdb调试下面的计算两个数之间的乘积和的一个程序
int main()
{
int count =1;
int sum = 1;
int n;
int limit_number;
printf("this program is to multiply between numbers!\n");
printf("Enter the limited numbers: ");
scanf("%d",&n);
if(n > 0)
{
while(count++ < n)
{
sum *= count;
}
printf("sum = %d\n",sum);
}
else if( n < 0 )
{
printf("wrong way input ,you should input > 0 numbers! try again!\n");
printf("Enter the limited numbers: ");
scanf("%d",&limit_number);
while(count++ < limit_number)
{
sum *= count;
}
printf("sum = %d\n",sum);
}
else
printf("the sum all equal to 0!,Bye\n");
return 0;
}
① 进入gdb调试
gcc -g test.c -o test
gdb test
② 使用l 命令查看
(gdb)l
③ 设置断点并查看断点 (gdb)b N 在N行设置断点 (gdb)info b 查看设置断点情况 ④ 运行
(gdb)n 单步运行,遇到函数不进入 (gdb)s 单步运行,遇到函数进入函数
⑤ 查看变量值 (gdb)r 运行代码 (gdb)p n 查看变量值n ⑥ 继续运行到下一个断点 (gdb)c 恢复程序运行码,直接运行到程序的下一个断点
2.3 gdb使用要点
- gcc编译选项中一定要加入 -g
- 只有在代码处于“运行”或者“暂停”状态时才能查看变量值
- 设置断点后程序在指定行之前停止
|