c语言目标使用无效的编译器,C语言编译过程

编译过程

总览图

8e5e2ce8fa204ab2acb30f323f8e7c37.jpg

预处理

在此阶段过程中,编译器会根据我们写好的代码,以此分析其中的语句,并对当中的某些语句执行替换,该替换是直接作用于.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++->选中预处理器->更选“预处理到文件”属性为是->点击应用再确定。

ca2146d6570e40649c3468a73d24709b.jpg

文件路径:再次点击生成解决方案->右键工程->选中“在文件资源管理器中打开文件夹(X)”->Debug目录下找到.i后缀的文件->.i后缀的文件便是通过了预处理之后的文件(该文件的代码量为膨胀为.c文件的好几倍)。

46df8ba99cd64614b900251b471a4635.jpg

编译

编译过程按顺序分两步:语句分析和代码优化。

语句分析:

对整体代码进行扫描处理,解析代码的词法、语法、语义,以此排除不合法的、不规范的代码。

词法解析:关键字的正确性、标识符的有效性、立即数的展开。

语法分析:变量命名规范、程序结构合法性、函数定义的正确性、重定义现象等。

语义分析:表达式的合理性、变量的未初始化使用等。

如若以上情况存在不合法性,编译器会停止编译并抛出错误同时显示该错误。

代码优化:

语句分析通过了之后,编译器会针对现有代码最后生成的汇编语句来进行优化处理。存在两种模式的代码优化方式: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

汇编器

针对生成的汇编代码,将其逐句解析转换生成一一对应的机器码(二进制编码)。

链接

由于在现有代码中使用了大量的外部指令(库或目标文件),而这些外部指令并非存在于我们本地代码中,因此没有生成的与之对应的机器码,如若没有与之对应的机器码,则程序无法正常运行,因此在将本地代码转换成汇编指令之后进入链接的过程操作,该操作由链接器来完成。

存在两种链接方式:静态链接和动态链接。

静态链接:

静态连接是在链接时将使用了的外部指令(库或目标文件的内容)加入到可执行程序(转换生成的二进制编码)中,即通过链接器将该文件与汇编器转换生成的汇编指令链接到一块生成可执行程序。

动态链接:

动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载外部指令的相应内容(比如:库文件,是预先编译链接好的可执行文件),存在在同一时间,多个应用可以使用一个外部指令的同一份拷贝,而操作系统不需要加载该指令的多个实例,即不再将他们的多个实例静态的对应链接在一起,而是在程序要运行时才进行链接对应的同一份拷贝指令。

二者之间区别:

静态链接会使得生成的可执行文件变大,占用更多的系统资源,该执行文件包含相同的公共代码,会造成浪费。

动态链接是由操作系统负责立即解析外部指令,然后代表应用调用合适的文件内容。由于每个调用都会存在系统开销,因此运行时链接的执行效率要慢得多,对应用的性能有负面影响。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值