C++的一些语言特性使之必须由编译器和链接器共同支持才能完成工作。最主要的有两个方面,其一,C++的重复代码的消除;其二,全局构造与析构。此外,由于C++的各种特性,比如虚函数、函数重载、继承、异常等,使得C++背后的数据结构异常复杂。而且最为不幸的是,这些数据结构往往在不同的编译器和链接器之间不能相互通用,使得C++程序的二进制兼容性成为一个难题。本篇博客将结合项目经验初步讨论C++程序的二进制兼容性问题。
1.C++中重复代码是如何消除的?
C++编译器在很多时候会产生重复的代码,比如模板(Templates)、外部内联函数(External Inline Function)和虚函数表(Virtual Function Table)都有可能在不同的编译单元里生成相同的代码。最简单的情况就是拿模板来说事,模板从本质上来讲很像宏,当模板在一个编译单元里被实例化时,他并不知道自己是否在别的编译单元也被实例化了。所以当一个模板在多个编译单元同时实例化成相同的类型的时候,必然会生成重复的代码。当然,最简单的方式就是不管这些,就将这些重复的代码都保留下来。但这会存在以下几个问题:
1.空间浪费。可以想象一个由好几百个编译单元的工程同时实例化了许多个模板,最后链接的时候必须将这些重复的代码消除掉,否则最终程序的大小坑定会膨胀的很厉害。
2.地址容易出错。有可能两个指向同一个函数的指针会不想等。
3.