- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
为什么 C++编译器不能支持对模板的分离式编译
首先,C++标准中提到,一个编译单元[translation unit]是指一个.cpp 文件以及它所 include 的所有.h 文件,.h 文件里的代码将会被扩展到包含它的.cpp 文件里,然后编译器编译该.cpp 文件为一个.obj 文件,后者拥有 PE[Portable Executable,即 windows 可执行文件]文件格式, 并且本身包含的就已经是二进制码,但是,不一定能够执行,因为并不保证其中一定有 main 函数。当编译器将一个工程里的所有.cpp 文件以分离的方式编译完毕后,再由连接器(linker) 进行连接成为一个.exe 文件。
举个例子:
//---------------test.h //
void f();//这里声明一个函数 f
//---------------test.cpp //
#include”test.h”
void f()
{
…//do something
} //这里实现出 test.h 中声明的f 函数
//---------------main.cpp //
#include”test.h”
int main()
{
f(); //调用 f,f 具有外部连接类型
}
在这个例子中,test. cpp 和 main.cpp 各被编译成为不同的.obj 文件[姑且命名为 test.obj 和main.obj],在 main.cpp 中,调用了 f 函数,然而当编译器编译 main.cpp 时,它所仅仅知道的只是 main.cpp 中所包含的 test.h 文件中的一个关于 void f();的声明,所以,编译器将这里
的f 看作外部连接类型,即认为它的函数实现代码在另一个.obj 文件中,本例也就是test.obj, 也就是说,main.obj 中实际没有关于f 函数的哪怕一行二进制代码,而这些代码实际存在于test.cpp 所编译成的 test.obj 中。在 main.obj 中对f 的调用只会生成一行 call 指令,像这样:
call f [C++中这个名字当然是经过 mangling[处理]过的]
在编译时,这个call 指令显然是错误的,因为main.obj 中并无一行f 的实现代码。那怎么办呢?这就是连接器的任务,连接器负责在其它的.obj 中[本例为 test.obj]寻找 f 的实现代码, 找到以后将 call f 这个指令的调用地址换成实际的f 的函数进入点地址。需要注意的是:连接器实际上将工程里的.obj“连接”成了一个.exe 文件,而它最关键的任务就是上面说的, 寻找一个外部连接符号在另一个.obj 中的地址,然后替换原来的“虚假”地址。
这个过程如果说的更深入就是:
call f 这行指令其实并不是这样的,它实际上是所谓的stub,也就是一个
jmp 0x23423[这个地址可能是任意的,然而关键是这个地址上有一行指令来进行真正的 call f 动作。也就是说,这个.obj 文件里面所有对f 的调用都 jmp 向同一个地址,在后者那儿才真正”call”f。这样做的好处就是连接器修改地址时只要对后者的call XXX 地址作改动就行了。但是,连接器是如何找到f 的实际地址的呢[在本例中这处于 test.obj 中],因为.obj 于.exe 的格式都是一样的,在这样的文件中有一个符号导入表和符号导出表[import table 和export table]其中将所有符号和它们的地址关联起来。这样连接器只要在 test.obj 的符号导出表中寻找符号 f[当然 C++对 f 作了 mangling]的地址就行了,然后作一些偏移量处理后[因为是将两个.obj 文件合并,当然地址会有一定的偏移,这个连接器清楚]写入 main.obj 中的符号导入表中f 所占有的那一项。
这就是大概的过程。其中关键就是:
编译 main.cpp 时,编译器不知道 f 的实现,所有当碰到对它的调用时只是给出一个指示,指示连接器应该为它寻找f 的实现体。这也就是说main.obj 中没有关于f 的任何一行二进制代码。
编译 test.cpp 时,编译器找到了f 的实现。于是乎f 的实现[二进制代码]出现在 test.obj
里。
连接时,连接器在test.obj 中找到f 的实现代码[二进制]的地址[通过符号导出表]。然后将 main.obj 中悬而未决的 call XXX 地址改成f 实际的地址。
完成。
然而,对于模板,你知道,模板函数的代码其实并不能直接编译成二进制代码,其中要有一个“具现化”的过程。举个例子:
//----------main.cpp //
templateclass T void f(T t)
您可能关注的文档
最近下载
- 中国行业标准 YY 9706.274-2022医用电气设备 第2-74部分:呼吸湿化设备的基本安全和基本性能专用要求.pdf
- 中秋博饼规则.doc VIP
- (人教2024版)英语七年级上册全册语法总复习(知识点+练习) 学生版+解析版_可搜索.pdf VIP
- 机械制图课件断面图.ppt VIP
- 《中外历史纲要(下)》填空.pdf VIP
- 高中政治2024届高考复习《逻辑与思维》真题练习(选择题+主观题)(附参 .pdf VIP
- 2025年咸阳市社区工作者计划招聘412人考试备考题库及答案解析.docx VIP
- 2025-2030中国生物可吸收输尿管支架行业市场发展趋势与前景展望战略研究报告.docx VIP
- 保健品专卖店管理制度.docx VIP
- 2025年高级审计师《高级审计实务》考试题库 .pdf VIP
文档评论(0)