一、gcc编译器
gcc对应的c语言的编译器(将程序员所写的高级语言代码解释为机器可以识别的二进制机器指令)
gcc常见选项:
-c 汇编完成后停止,不进行链接
-E 预处理完成后停止,不进行编译
-S 编译完成后停止,不进行汇编
-o 用于指定目标文件名称
-g 生成debug程序。向程序中添加调试符号信息
编译过程:
- 编译过程为 扫描程序-->语法分析-->语义分析-->源代码优化-->代码生成器-->目标代码优化;
- 扫描程序进行词法分析,从左向右,从上往下扫描源程序字符,识别出各个单词,确定单词类型
- 语法分析是根据语法规则,将输入的语句构建出分析树,或者语法树,也就是我们答案中提到的分析树parse tree或者语法树syntax tree
- 语义分析是根据上下文分析函数返回值类型是否对应这种语义检测,可以理解语法分析就是描述一个句子主宾谓是否符合规则,而语义用于检测句子的意思是否是正确的
- 目标代码生成指的是,把中间代码变换成为特定机器上的低级语言代码。
预处理:引入头文件,去除注释,宏替换,条件编译
gcc -E main.c -o main.i
编译:进行语法语义纠错,构建语法语义树,没有错误则解释为汇编指令
gcc -S mian.i -o mian.s
汇编:将汇编指令解释为二进制机器指令
gcc -c main.s -o main.o
链接:将所有.c文件生成的二进制机器指令以及还有库,打包到一起生成可执行程序
gcc main.o…… -o main
运行程序:告诉机器程序位置(绝对路径或相对路径)
./main(当前目录下的相对路径)
/a/b/c/main从根目录下开始的绝对路径
库:一个大量函数进行编译后生成的二进制机器指令打包到一起的文件(里面有大量的接口可以使用)需要进行链接
链接方式:
动态链接:链接时将库中的函数符号记录到可执行程序中
生成的可执行程序规模小,多个程序可是使用同一份库代码
运行时库需要加载到内存中,否则无法访问,如果删除了,就无法运行了
类似于引入一段目的地址,记录了函数的入口地址,当程序运行时一整个库都要带上,否则代码就会无法识别这个地址通到的位置
静态连接:将库中使用到的函数具体实现的指令拷贝一份到可执行序列中
将整段代码拷入,可见代码可执行序列偏大,同一份代码也可能也会有多份冗余
优点:无运行依赖
二、gdb调试
调试的前提:程序处于debug版本下
debug版本:调试版本,加入调试信息,不进行优化
realease版本:发布版本,对代码进行优化,不能调试
使用 *.i 来表示所有以.i为后缀的文件,rm *.i 表示删除当前目录下所有以.i结尾的文件
gcc编译器默认生成的是realease版本,如果想要生成debug版本需要加上-g选项
以下为默认的realease版本无法进行调试
以下为debug版本可以正常进行调试
其他相关指令:
1、使用gdb
gdb ./main gdb + 文件路径
2、开始调试:
start 开始逐步调试F5 run 直接运行 == VS中 Ctrl+F5
3、逐行调试:
next 下一步 逐过程(遇到函数直接把函数运行完)
step 下一步 逐语句(遇到函数,进入函数)
unti main.c:18 直接运行到指定文件的指定行
4、查看代码:
list 显示代码
list main:18 显示指定行处代码
5、断点操作:
break mian.c:18 给18行下一个断点
break func_name 给该函数处打断点
info break 差点断点信息
delete break_id 删除指定断点
continue 从当前调试位置开始继续向下运动到下一个断点位置,如果后面没有断点则会
运行到结束
三、make 与 makefile
makefile中的伪对象
表示对象名称并不代表真正的文件名,与实际存在的同名文件没有相互关系,因此伪对象不管同名目标文件是否存在都会执行对应的生成指令。
伪对象的作用有两个,
1. 使目标对象无论如何都要重新生成。
2. 并不生成目标文件,而是为了执行一些指令。
3、makefile中使用 .PHONY 来声明伪对象
makefile 创建使用:
make 运行
- makefile文件中,保存了编译器和链接器的参数选项,并且描述了所有源文件之间的关系。make程序会读取makefile文件中的数据,然后根据规则调用编译器,汇编器,链接器产生最后的输出。根据makefile的功能理解,A选项是正确的
- Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释, B选项是正确的
- 显式规则说明了,如何生成一个或多个目标文件。
- make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写makefile,比如源文件与目标文件之间的时间关系判断之类
- 在makefile中可以定义变量,当makefile被执行时,其中的变量都会被扩展到相应的引用位置上,通常使用 $(var) 表示引用变量
- 文件指示。包含在一个makefile中引用另一个makefile,类似C语言中的include; 根据这一项可以推导D选项是错误的。
- 注释,makefile中可以使用 # 在行首表示行注释
- 默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件
死代码删除是编译最优化技术,指的是移除根本执行不到的代码,或者对程序运行结果没有影响的代码,而并不是删除被注释的代码
内联函数,也叫编译时期展开函数, 指的是建议编译器将内联函数体插入并取代每一处调用函数的地方,从而节省函数调用带来的成本,使用方式类似于宏,但是与宏不同的是内联函数拥有参数类型的校验,以及调试信息,而宏只是文本替换而已