本视频主要介绍了c代码的【编译】过程。
编译过程
就是计算机把我们敲得代码转换成它认识的可以执行的代码的过程。(众所周知计算机认识的是机器代码 01010101)
总体可分为四个步骤(集成开发环境其实会把这个变化隐藏掉,实际一般情况下我们只关心.c和可执行文件.exe即可):
预处理、编译、汇编、链接
预处理:把代码中的预处理指令替换为真正的指令,包括#include
等,简单讲就是文本替换。后缀变化 【.c】→ 【.i】
编译: 经过词法分析、语法分析、语义分析、中间代码生成及优化等等一系列中间操作(编译器主要干的活,详见《编译原理》)把原本的c代码转化为汇编指令。后缀变化【.i】→ 【.s】
汇编: 翻译(汇编→机器指令,MOV → 0101010巴拉巴拉),把每一个【.s】文件都翻译成【.o】文件(众所周知每一个工程都可能有很多个.c文件,这样就会生成很多.o文件)学名:可重定位目标文件
链接: 现在我们有很多个.o文件了,它们之间可能有互相调用的关系。举例:我们使用printf打印变量,这个printf在printf.o这个文件中,所以它们需要某个工具连接起来跳过去那个文件才可以正常执行(大概也不一定要跳过去)。这个就是链接的作用。所以链接的功能是:按一定规则合并这些.o文件。后缀变化【.o】→【 】(视频里的可执行目标文件无后缀,可能是因为linux系统?)
学习编译过程的理由:
- 优化程序性能
- 理解链接错误(这个真的真的真的经常遇到)
- 避免安全漏洞(例如缓冲区溢出)
思考:
- switch 比 if-else 高效吗?(3/5)
- 一个函数调用的开销有多大?(3/5)
- while 比 for 高效吗?(3/5)
- 静态变量和全局变量的区别是什么?(7)
- 静态库和动态库的区别是什么?(7)
- 数据和控制信息在程序栈上如何存储?(3)
毫不谦虚地说,以上这些问题我都研究过,但是现在都忘了(焯,好气。
数字为《csapp》章节数