GCC
1、GCC编译过程
首先使用编辑器对.c文件进行编辑,即:敲代码。之后GCC编译器会对.c文件进行预处理、编译、汇编、链接,最终输出可执行文件。具体流程如下:
四个阶段的含义及指令
1、预处理
指令:gcc - E <.c文件> -o <.i文件>
预处理阶段会将以" # "开头的代码进行处理。比如展开#include的文件,替换宏定义#define的值。
2、编译
指令:gcc -S <.i文件> -o <.s文件>
编译阶段会检查代码的语法错误,并把文件中的C语言转为汇编语言存入.s文件中
3、汇编
指令:gcc -c <.s文件> -o <.o文件>
汇编过程会将文件中的汇编语言转为二进制文件,也称为目标文件。
4、链接
指令:gcc <.o文件> -o <可执行文件>
链接过程为进行链接库函数,之后生成可执行文件。
gcc编译简易步骤
gcc可以不从-E开始执行,可以直接从汇编开始:gcc -c <.c文件> -o <.o文件>,之后再进行链接。
再简化,也可以gcc <.c文件> -o <可执行文件>
2、GCC常用选项
gcc的选项除了编译中4个步骤中用到的-E、-S、-c,还有以下选项:
- -g:生成的文件可以进行GDB调试
- -O、-O2:优化编译
- -I(大写的i):用于指定存放头文件目录的路径。示例在 " 3、分文件处理 " 章节
- -l(小写的L):用于连接库,比如线程中需要gcc -lpthread
- -L:指定库的路径
3、分文件处理
分文件处理指令:gcc <多个.c文件> -o <可执行文件> -I <头文件路径>
1、编写好各个文件
2、gcc编译
4、条件编译
指令:gcc <.c文件> -o <可执行文件> -D <宏名>=<值>
示例一:不加参数的#define
示例二:加参数的#define
GDB
1、GDB相关指令
注意:使用GDB之前,GCC编译需要加上-g选项
1、开始GDB调试
gcc -g <.c文件> -o <可执行文件>
gdb <可执行文件>
2、查看代码内容:list,简写l。后加数字n,显示第n行附近的代码
3、设置断点:break,简写b。后面可以跟行号或者函数名
查看有哪些断点:info b
下面例子,在main和第10行进行打断点
4、运行:run,简写r。如果有断点,会自动停在断点位置。
run如果没有断点,则会直接运行到程序退出。如果想单步运行可以用start
5.1 执行到下一个断点:c
5.2 一步一步运行:next,简写n。会跳过函数,不进入内部
5.3 一步一步运行:step,简写s。会进入函数,查看函数内容
6、打印变量值:print,简写p。后面加变量名
7、退出GDB:quit
8、查看栈信息:bt
9、查看停止信息:edit
10、帮助手册:help
2、GDB调试段错误
当代码编译产生段错误时,会自动生成一个core文件。
使用"gdb <可执行文件> core"即可对段错误发生位置进行调试。
1、允许产生core文件:sudo service apport stop
2、使用gdb找到段错误的位置
3、查看源码,修改段错误
3、GDB调试正在运行的进程
1、查询进程pid:ps -aux | grep <进程名>
2、进行GDB调试:gdb ./a.out -p <进程号>。之后正常调试即可。
4、GDB调试多进程程序
1、开始gdb调试
2、使用start进行单步运行,进入调试
3、设置当前调试的进程,默认调试父进程
set follow-fork-mode child:调试子进程
set follow-fork-mode father:调试父进程
set detach-on-fork off:设置可以同时调试父子进程
4、查询gdb当前跟踪的进程:info inferiors
5、切换到指定的进程,对该进程进行调试:inferiors <Num>:
gdb调试代码如下:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
int main(){
pid_t pid;
if((pid = fork())<0){
perror("fork");
return -1;
}else if(pid > 0){
printf("this is father 1\n");
printf("this is father 2\n");
printf("this is father 3\n");
}else{
printf("this is child 1\n");
printf("this is child 2\n");
printf("this is child 3\n");
}
return 0;
}
5、GDB调试多线程
显示程序中的线程:info thread
切换到指定线程:thread <Id> 这个id就是info thread查出来的id
设置线程锁:set scheduler-locking on 只允许当前线程运行,off代表多线程同时运行
为特定线程设置断点:b <位置> thread <Id> 这个id就是info thread查出来的id