面经笔记本 语言基础理论 【二:程序的编译与链接】
作者:互联网
目录
一、翻译环境与运行环境
在ANSI C的任何一种实现中,存在两个不同的环境:翻译环境和执行环境。
注:ANSI C是美国国家标准协会对C语言发布的标准
翻译环境:
.c文件经过编译加链接,成为.exe的可执行文件。
在这个环境中,源代码被转换为可执行的机器指令;
执行环境:
用于实际执行代码。
二、编译与链接
2.1 大体介绍
组成一个程序的每个源文件会先通过编译,成为目标代码。
此时每个源文件的后缀名为.obj
每个目标文件再由链接器捆绑在一起,这个阶段叫做链接,
形成了一个单一而完整的可执行程序。
后缀为.exe。
链接器还会引入标准C函数库或个人程序库中,任何被该程序所用到的函数。
编译本身也分三个阶段:
预编译-编译-汇编
2.2 预编译阶段
将.c文件进行预编译,转换成.i文件。
这个阶段进行预处理指令,
比如:
1.注释删除
2.把define定义的符号换成值
这个阶段做的是文本操作。
2.3 编译阶段
把C代码翻译成汇编代码。
我们会进行语法分析,词法分析,语义分析,最后进行符号汇总。
2.4 汇编阶段
把汇编代码转换成二进制代码,
形成.o文件
.o文件里放的已经是二进制的指令了。
整个编译完成后,每个源文件都会生成一个.obj文件,
然后进行链接,形成.exe的可执行文件。
2.5 链接
链接阶段做两件事:
1.合并段表
2.符号表的合并和重定位
2.6 运行环境
程序执行的过程:
1.程序必须载入内存中。(一般由操作系统来完成)
2.程序的执行开始,首先调用main函数
3.开始执行程序代码,这个时候程序将使用一个运行时堆栈,存储函数的局部变量和返回地址。程序还可以使用静态内存,这里面的变量在程序的整个执行过程中一直保留他们的值。
3.终止程序。
三、宏
3.1 宏与函数的对比
1.代码长度
每次使用时,宏代码会被插入到程序中。
而函数代码只出现于同一个地方。
2.执行速度
宏更快,因为函数存在调用和返回的额外开销。
3.宏是类型无关的。
4.宏不方便调试。
5.宏无法递归。
3.2 宏与内联函数的对比
3.2.1 内联函数
引入内联函数,是为了解决程序中函数调用的效率问题。
程序在编译器编译的时候,编译器会将程序中出现的内联函数调用表达式,用内联函数的函数体进行替换。
而普通函数,并不是在编译的时候被替换,而是在运行的时候被替换。
这其实是一个以空间代价换取时间代价的节省,
所以内联函数一般都是10行以内的小函数。
在声明内联函数时,我们要使用inline关键字。
内联函数有两点注意:
1.不允许使用分支与循环
2.内联函数的定义必须出现在内联函数第一次调用前
优点:当函数体比较小时,内联函数效率高;
缺点:滥用内联会导致程序变慢。
3.2.2 宏
预处理器用复制宏代码的方式代替函数调用,省去了参数压栈、生成汇编语言的CALL调用、返回参数、执行return等过程,从而提高了速度。
内联函数和宏的区别:
内联函数和宏类似的一点在于,内联函数和宏都是在程序运行前,整个编译阶段,进行代码的替换。
区别在于,内联函数是通过编译器来替代的,而宏是通过预处理器来替代的。
而且,传统的宏定义可能会引起一些麻烦,
举个例子:
#define SQUARE(x) x*x
这是一个将参数平方的函数,
我们来运用一下:
int a = 5;
cout<<SQUARE(a+1);
乍一看,我们会以为是36,
但其实,宏只是一个单纯的替换,
在这里,经过预处理器的替换,SQUARE(a+1)会变成 a+1*a+1,也就是11.
并不符合我们的逻辑。
所以我们应该这样写:
#define SQUARE(x) (x) * (x)
而且,宏是没有参数类型检查的,这会产生安全问题。
但是,如果我们使用内联函数,就不会有这样的问题出现。
内联函数可以得到宏的替换效能,还可以得到常规函数的类型检查。
标签:函数,面经,程序,编译,3.2,内联,基础理论,链接 来源: https://blog.csdn.net/Kukeoo/article/details/117791124