一、调试器
调试器的功能:调试、观察程序的运行过程,通常目的都是为了排查程序的运行错误。
程序的错误分类:编译错误、链接错误、运行时错误(运行中逻辑错误以及程序运行时崩溃)。
调试程序的前提:程序必须是一个debug版本的程序。由于gcc/g++默认生成release版本程序,因此若要生成debug版本,则使用-g选项gcc -g test.c -o test。
可执行程序的分类:debug调试版不对代码进行优化,并且加入程序调试信息;release发布版包含调试信息,并且会对代码进行优化。
gdb常用调试指令:gdb ./test.exe
流程控制指令
run:直接运行程序
b或break:打断点。示例:break test.c:14 break function_name
start:开始逐步调试
ib或info break:查看断点信息
list:查看调试行附近代码。示例:list test.c:12
d或delete:删除断点。示例:delete id
n或next:下一步(逐过程,遇到函数直接运行完毕)
watch:变量监控断点,当变量发生改变的时候停下来。示例:watch variable_name
s或step:下一步(逐语句,遇到函数则进入函数继续调试)
q或quit:退出gdb调试
until:直接运行到指定位置。示例:until test.c:16
c或continue:继续从当前调试位置运行
内存控制指令
p或print:查看或设置变量内容。示例: print var_name、print var=val
bt或backtrace:查看函数调用栈(通常用于检测程序运行时崩溃位置)
栈顶位置的函数就是程序发生崩溃的的位置,例如下图:
二、项目的自动化构建工具
Makefile
是一个文本文件,记录一个项目的构建规则流程。
make
是一个解释程序,对Makefile中记录的构建规则流程逐步解释执行,完成项目的构建。
make的解释执行规则:
1、在命令行中敲击make指令,则表示运行make解释程序,程序会在当前目录下找到名称为makefile/Makefile的文件,解释执行其中的项目构建规则。
2、在规则中,找到要生成的第一个目标对象,(判断目标对象是否已经存在,存在的话是否需要重新生成–根据源码文件的最后一次修改时间对比),然后执行对象生成这一命令。
3、make每次在makefile中只会找到第一个目标对象进行生成,生成之后就会退出(即不会生成第二个对象)。
4、make在生成目标对象的时候,会先查找依赖对象的生成规则,先生成依赖对象,然后再去生成目标对象。
makefile的编写规则:
目标对象:依赖对象
\t为了生成目标对象要执行的指令
预定义变量的使用: $@表示目标对象,$^表示所有依赖对象,$<表示依赖对象的第一个
例如:
等价于:
等价于:
程序的编译过程:预处理,编译,汇编,链接。在项目构建中会整体分为两步:编译与链接。
这样的好处是:如果只是修改了一个.c文件,对所有.c进行编译生成可执行程序的过程来说,需要重新编译所有.c生成可执行程序,效率低下。因此分为两步进行操作,先把每个.c都生成自己的.o,然后再把所有的.o链接到一起。一旦一个.c发生改变,只需要对这一个.c进行编译生成.o之后。重新链接一次就可以生成可执行程序(其他的.c不需要重新编译)。
如下所示:
分别生成.o文件,再链接生成可执行程序test。
修改了test.c文件后,只需要重新生成test.o文件,再将所有.o文件重新链接一次生成可执行程序test即可。
因此,makefile应该编写如下:
以上代码可以简化为:
再作一些优化可得:
伪对象(即.PHONY:):声明一个目标对象与外部文件无关,表示每次这个对象不管是否最新都要重新生成。
加入伪对象,防止要生成的对象与外部文件重名,保证make之后能生成正确的目标对象。完整代码如下: