一:调试工具gdb的使用
1.使用gdb的前提是程序是debug版本
-----gcc/g++默认生成release版本,若要生成debug版本,则使用-g选项,例如:gcc -g test.c -o test
程序的版本:
(1)debug(调试版):不对代码进行优化,并且加入程序调试信息;
(2)release(发布版):不包含调试信息,并且会对代码进行优化。
2.gdb常用调试指令:gdb ./test/exe
(1)流程控制
Part A:
简写(这些简写大小写都可以)
r run:直接运行程序
start:开始逐步调试
l list:查看调试行附近代码(范围是调试行的上五行到下五行)
list 文件名:行号 示例:list test.c:10
list 行号 示例:list 11
n next:下一步,逐过程,遇到函数直接运行完毕
s step:下一步,逐语句,遇到函数直接进入函数内部进行调试
until:直接运行到指定位置
示例:until 文件名:行号
c continue:继续从程序当前位置运行,直至遇到断点或程序结束
q quit:退出调试
Part B:断点相关指令
b break:打一个断点
break 文件名:行号 -------给指定文件的某一行打断点
break test.c:10
break 函数名 -------给函数打断点(给函数的第一行打断点)
break Fun
i b info break :查看断点信息
d delete 断点id:删除断点
watch 变量名:创建一个变量监控断点 ---当变量发生改变时停下来
(2)内存控制
p print:查看或设置变量的值
print 变量名 print 变量名=变量值
示例:print i print i=10
bt backtrace:查看函数调用栈 -----通常用于检测程序运行时崩溃位置
函数调用栈:
在程序运行过程中,先调用的函数先入栈,函数调用结束后出栈;
如果运行出现错误,则出错的函数还没有出栈,那么函数调用栈的栈顶位置就是出错位置
二.项目自动化构建工具make/Makefile
1.Makefile:一个文本文件,记录一个项目的构建规则流程
(1)Makefile的编写规则:
①基本编写规则:
目标对象:依赖对象
制表符(Tab) 生成目标对象要执行的指令
示例:
②预定义变量的使用
$@:目标对象
$^:所有依赖对象
$<:依赖对象的第一个
使用预定义变量后示例:
A.优化一
B.优化2--------不论有多少文件,都可以生成目标文件,减少重复的操作
#是注释符号
定义一个普通变量src,通过$(wildcard ./*.c)获取当前目录下所有的.c文件,
通过 $(src)使用src变量包含的文件
③程序的编译过程
之前的编译过程分为四步:预处理,编译,汇编,链接;
makefile在项目构建中会整体分为两步,编译与链接;
编译包括预处理、编译、汇编三个模块
分为两步的好处:
如果只是修改了一个.c文件,以前对所有.c进行编译生成可执行程序的过程,需要重新编译所有的.c文件生成可执行程序,效率低下。但分为两步走时,先把每个.c文件生成自己的.o文件,然后再把所有的.o链接到一起,若对其中的一个.c文件进行修改,只需要对这个.c文件进行编译生成.o之后,重新链接一次就可以生成可执行程序,而其他的.c文件不需要重新编译。
④伪对象
声明一个对象和外部文件无关,每次生成时无论这个对象是不是最新都要重新生成,这样的对象就是伪对象。
也就是说,如果有对象不管外部是否存在,每次无论如何都要执行,就可以声明为伪对象。
对应的格式为 .PHONY:对象名
通常伪对象用于额外对象如下面例子中的clean命令上,防止和外部文件重名
示例:
例1:调用make clean命令清除文件
Makefile内:
例2:每次调用make指令时不管存不存在test文件都会重新生成
Makefile文件内:
例3:将clean命令声明为伪对象,防止和外部文件重名
例4:
2.make:是一个解释程序,对Makefile中记录的构建规则流程逐步解释执行,完成项目的构建
(1)make的解释执行规则
①在命令行敲击make指令,则表示运行make解释程序,程序会在当前目录下找到名为Makefile或makefile的文件,解释其中的项目构建规则;
②在规则中,找到要生成的第一个目标对象,(判断目标对象是否已经存在,存在的话是否需要重新生成-----根据原码文件的最后一次修改时间对比),然后执行对象生成这一指令;
③ make每次在Makefile中只会找到第一个目标对象进行生成,生成之后就会退出(也就是说不会生成后面的对象);
示例:
只会生成test.o,不会生成test1.o和test2.o
④make在生成目标对象时,会先查找依赖对象的生成规则,先生成依赖对象,然后再去生成目标对象(简而言之就是为了生成目标,先生成依赖);
示例:
上面例子的进一步优化:
%是通配符,%.o:%.c这一条语句的作用是将每一个.c文件按照对应的规则生成 对应的.o文件
继续优化:
上面的语句的作用是:用src变量中的所有的.c文件生成对应的.o文件,然后将这些.o文件存放到obj变量中