今天看 C++在编译链接过程中的相关问题。
C++由于类的特殊性,一些内容必须由编译器和链接器共同支持才能完成工作(重复代码消除,构造函数,析构函数)。而且C++中的一些特性如虚函数、重载、继承等,背后的数据结构非常复杂,还会导致不同编译器和链接器之间相互不能通用。
首先看了4.4.1,重复代码消除
C++的某些特性会出现:在多个编译单元内多次被实例化的情况,如果简单的将重复的代码都保存下来,那么主要有以下几个问题:
1. 空间浪费
2. 地址较易出错(?)
3. 执行效率低,主要指cpu的指令cache命中率降低
GCC和Visual C++都对此进行了优化,方式类似,都采用单次链接的方式,重复的代码段将会被丢弃。
全局构造和析构
C++的构造函数在main之前执行,main之后会执行析构函数。
在main之前执行的,还有堆分配初始化(malloc、free),线程子系统等。
C++的ELF文件中,还有两个特殊的段:
.init:main函数之前执行的代码段
.fini:main正常退出之后执行的代码段
若用户将自定义的函数放在.init或.fini段内,则会在对应时间执行对应的代码段。
C++与ABI
不同编译平台的目标文件若可以相互链接,则必须满足下面的条件:
1. 采用相同的目标文件格式
2. 拥有同样的符号修饰标准
3. 变量的内存分布方式相同
4. 函数的调用方式相同
5. ……
上面五点这些和可执行代码二进制兼容性相关的内容成为ABI(Application Binary Interface)
ABI和API的区别
其实两者都是应用程序接口,但是层面不同,API为源代码层面的,ABI为二进制层面的。