1.翻译环境和运行环境
- 代码都是文本信息,计算机是不能直接识别的,计算机可以直接执行的是二进制指令
- C语言代码是需要经过处理的,怎么处理呢?是通过编译器处理的。
- 在ANSI C(标准c)的中有两种不同的环境。
- 翻译环境,这个环境中源代码会被翻译为可执行的(机器指令)二进制指令
- 运行环境,执行代码
- 在调试时运行的程序,是通过翻译环境生成的后缀.exe的文件
2.翻译环境
- 在写项目的时候会有多个.c文件,他们通过每个都通过编译器的处理,各自都生成了一个目标文件
- 多个目标文件和链接库一起通过链接器处理生成的可执行程序
2.1预处理(预编译) test.i
gcc test.c -E -o test.i
-
- -E 意思是在预处理阶段停下来
- -o 想让它生成的文件是 test.i
- 编译有可以分为细分为三个过程 预处理 ——> 编译 ——> 汇编
- 完整的过程:C代码 ——> 预处理 ——> 编译 ——> 汇编 ——> 链接 ——> 可执行程序
- 在预处理阶段,源文件和头文件会被处理成后缀为 .i 的文件。
- 预处理阶段主要处理 #include #define这样的源文件。处理所有的条件编译比如: #if、#ifedef、#elif、#endif等等
- 删除所有的#define,并且展开所有的宏定义,用完就会删,通过预处理阶段,MIN被替换,看下面例子,右下角的截图来自test.c的文件
- 会删除所有的注释,真正运行代码的时候一行注释都没有,注释是给程序员看的
- 假如有头文件包含头文件,会递归的形式展开。还会添加行号和文件名标识,方便后面编译器生成调试信息
- 保留所有的#pragma的编译器命令,编译器后续会用,
- 就好比#pragma pack(),这个可以修改结构体的默认对齐大小
- 还有一个#pragma once ,这个是防止头文件重复包含
- 下面的例子就很好的说明了问题,#pragma定义确实会保留
2.2编译 test.s 汇编代码
- 编译过程是预处理之后的,有三个步骤:词法分析,语法分析,语义分析生成对应的汇编代码文件
gcc -S test.i -o test.s
- -S 对中间文件处理,可以放在test.i前后都没问题,最后生成test.s文件的汇编代码
- 把C语言代码生成了汇编代码,大家可以去gcc的环境下试试哈
2.2.1三个步骤
1. 词法分析器
- 扫描器,就是简单的进行词法分析,把代码分割成不同的记号 (关键字、标识符、字面量、特殊字符等 ),就是把这个一句话拆分成成很多部分,括号,字符,数字,符号,关键字等
2. 语法分析器
- = 对应赋值,+ 加法表达式 ,* 乘法表达式 arr 标识符等等
- 可以产生语法书,表达方式是为节点的树。根据表达式的关系构成语法书
3. 语义分析器
-
- 对表达式的语法层面分析,分析的是语义的静态分析,大概的分析语义,并没有执行。
- 如果有语法错误会提前报错,就是好比有时候写代码写着写着突然就会有个红色小波浪。
- 这个阶段可以知道每个表达式的类型是什么,当然这个过程很复杂的,相当于又是一个专业细分,我们了解一下就ok啦
- 大家应该还记得,sizeof 操作符吧,sizeof括号内是不可以计算的,为什么能输出4,都是这个阶段分析出来的
2.3汇编
gcc -c test.s
生成目标文件- 汇编器将汇编代码转换成机器可执行的二进制指令,每个汇编代码都有对应的机器指令
- 这个阶段会生成目标文件 test.o test.obj,这种文件是没法打开的里面是二进制
2.4链接
链接解决的是⼀个项目中多文件、多模块之间互相调用的问题。
- 把一堆文件链接在一起生成可执行的目标文件 .exe
- 每个.c 文件之间都有对应的符号表,符号有对应的地址,把他们整合起来,两个.c文件都有这个地址,但是只能有一个地址,编译器会自己选择有效的地址
- 所以调用的地方和声明的地方要符号统一才能找到
- 看报错,没办法解析外部符号,所以符号要一样才行
- 我们知道,在预处理的时候后有多个.c 文件一起执行,经过编译的过程,生成对应的.o和.obj文件等待被链接,编译器需要通过符号表,引用符号来找到对应正确的地址。因为在等待链接的过程生成了多个地址,编译器需要将相同与之对应符号修正过来成为真正可用的地址。这个过程叫做:重定位
3.运行环境
- 程序必须载入内存中,一般都是系统完成。在独立环境里面,程序的载入需要手工安排。还可以通过可执行代码置入只读内存来完成
- 程序开始就会调用main函数
- 执行代码程序的时候,程序会使用一个运行时间的堆栈(stack),存放局部变量和返回地址,程序也可以同时使用静态(static)内存,存在静态内存里面的会一直保存,直到程序结束
- 终止程序,正常终止main函数,可能半路意外终止
总结:
- 如果本篇文章对你有帮助,还请留下一键三连,我会继续努力创作出更加详细的文章,重点是理解消化这个过程,特别是在写出BUG的时候,你要知道是在哪个阶段出的问题,可以更好的入手解决问题。
- 坚持下去认为对的事情~~