在此阶段过程中,编译器会根据我们写好的代码,以此分析其中的语句,并对当中的某些语句执行替换,该替换是直接作用于.c文件。
分别处理:注释、#define、条件编译指令、#include。
#include
#define MAXLENGTH 20
int main()
{
int i = 0;
int j = MAXLENGTH;
#ifndef GOOGLE_VERSION
i +=j;
#endif
printf("%d", i);//未定义GOOGLE_VERSION 输出20
return 0;
}
在VS下点击“生成解决方案”会执行编译操作,编译第一步执行的便是预处理,生成预处理文件(VS下需进行些许设置才可看见)
相应设置:资源管理器下右击工程->选择属性->点击C/C++->选中预处理器->更选“预处理到文件”属性为是->点击应用再确定。
文件路径:再次点击生成解决方案->右键工程->选中“在文件资源管理器中打开文件夹(X)”->Debug目录下找到.i后缀的文件->.i后缀的文件便是通过了预处理之后的文件(该文件的代码量为膨胀为.c文件的好几倍)。
编译过程按顺序分两步:语句分析和代码优化。
对整体代码进行扫描处理,解析代码的词法、语法、语义,以此排除不合法的、不规范的代码。
词法解析:关键字的正确性、标识符的有效性、立即数的展开。
语法分析:变量命名规范、程序结构合法性、函数定义的正确性、重定义现象等。
语义分析:表达式的合理性、变量的未初始化使用等。
如若以上情况存在不合法性,编译器会停止编译并抛出错误同时显示该错误。
语句分析通过了之后,编译器会针对现有代码最后生成的汇编语句来进行优化处理。存在两种模式的代码优化方式:Debug和Release。
Debug:调试版本,生成便于调试的汇编指令;会根据现有的每一句代码生成对应的汇编语句,存在将现有的一句语句代码细化为几句汇编语句。旨在方便开发者逐句调试代码。
如下为以上程序的Debug版本下的反汇编代码:
#include
#define MAXLENGTH 20
int main()
{
01061790 push ebp
01061791 mov ebp,esp
01061793 sub esp,0D8h
01061799 push ebx
0106179A push esi
0106179B push edi
0106179C lea edi,[ebp-0D8h]
010617A2 mov ecx,36h
010617A7 mov eax,0CCCCCCCCh
010617AC rep stos dword ptr es:[edi]
int i = 0;
010617AE mov dword ptr [i],0
int j = MAXLENGTH;
010617B5 mov dword ptr [j],14h
#ifndef GOOGLE_VERSION
i += j;
010617BC mov eax,dword ptr [i]
010617BF add eax,dword ptr [j]
010617C2 mov dword ptr [i],eax
#endif
printf("%d", i);//未定义GOOGLE_VERSION 输出20
010617C5 mov esi,esp
010617C7 mov eax,dword ptr [i]
010617CA push eax
010617CB push 10658A8h
010617D0 call dword ptr ds:[1069114h]
010617D6 add esp,8
010617D9 cmp esi,esp
010617DB call __RTC_CheckEsp (010611D1h)
return 0;
010617E0 xor eax,eax
}
010617E2 pop edi
010617E3 pop esi
010617E4 pop ebx
}
010617E5 add esp,0D8h
010617EB cmp ebp,esp
010617ED call __RTC_CheckEsp (010611D1h)
010617F2 mov esp,ebp
010617F4 pop ebp
010617F5 ret
Relase:发行版本,不会为无效的过程操作(与结果无关)生成汇编指令,旨在降低程序的内存、提高程序的运行速度。
如下为以上程序的Relase版本下的反汇编代码:
int i = 0;
int j = MAXLENGTH;
#ifndef GOOGLE_VERSION
i += j;
#endif
printf("%d", i);//未定义GOOGLE_VERSION 输出20
00FB1000 push 14h
00FB1002 push 0FB2100h
00FB1007 call dword ptr ds:[0FB2090h]
00FB100D add esp,8
return 0;
00FB1010 xor eax,eax
}
00FB1012 ret
--- f:\dd\vctoo
针对生成的汇编代码,将其逐句解析转换生成一一对应的机器码(二进制编码)。
由于在现有代码中使用了大量的外部指令(库或目标文件),而这些外部指令并非存在于我们本地代码中,因此没有生成的与之对应的机器码,如若没有与之对应的机器码,则程序无法正常运行,因此在将本地代码转换成汇编指令之后进入链接的过程操作,该操作由链接器来完成。
存在两种链接方式:静态链接和动态链接。
静态连接是在链接时将使用了的外部指令(库或目标文件的内容)加入到可执行程序(转换生成的二进制编码)中,即通过链接器将该文件与汇编器转换生成的汇编指令链接到一块生成可执行程序。
动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载外部指令的相应内容(比如:库文件,是预先编译链接好的可执行文件),存在在同一时间,多个应用可以使用一个外部指令的同一份拷贝,而操作系统不需要加载该指令的多个实例,即不再将他们的多个实例静态的对应链接在一起,而是在程序要运行时才进行链接对应的同一份拷贝指令。