刘未鹏|C++的罗浮宫

Knowledge sharing is the best reuse

用户操作
[即时聊天] [发私信] [加为好友]
刘未鹏ID:pongba
1110818次访问,排名26,好友48人,关注者283人。
兴趣:人工智能、机器学习、认知科学、神经科学、心理学、行为经济学、数学、计算机科学。
pongba的文章
原创 108 篇
翻译 8 篇
转载 0 篇
评论 1939 篇
刘未鹏的公告
除非特别声明,本站采用Creative Commons License许可。转载请保留作者、出处。非商业。

FeedSkyFeedBurner
或者用 鲜果 GR 抓虾 订阅。

CSDN Blog暂不支持RSS全文输出,对此感到不便的朋友可以使用强大的greasemonkey脚本:GReader Preview Enhanced(链接),该脚本支持在GReader里面直接打开全文页面。

我经常出没于TopLanguage

《C++的罗浮宫》5年选集

——知识分享是最大的复用

下载地址:csdn资源频道|mediafire

讨论问题请到TopLanguage综合技术讨论组

TopLanguage

精彩言论@TopLanguage


pongba的共享阅读@Delicious


pongba@Twitter


pongba在读@豆瓣


gtalk/msn(邮件请发送到gmail邮箱)

pongba@gmail.com
pp_liu@msn.com

搜索(不要回车,点击Go)


pongba翻译的





这个Blog上都写了哪些东东

最近评论
AQINGLAU:楼上说的注解和补充,如果太多了会让人觉得是画蛇添足,对于必要的表达夹杂点英文词句未尝不可
tankin:很喜欢这篇文章,看了很久,一直想知道这种启迪思维的书到底有没有,今天知道了,是有的,而且很早就有了,不知道主人家还有什么好书可以推荐么?就是这种启迪思维的好书,小弟计算机系刚刚毕业,工作半年,发现工作完了,还是看书,看好书最爽啊
看牛人的blog也很爽,比如主人家的这个blog,平时我尽是看了,没什么言语,但如果有机会,也是滔滔敬佩之言辞
韩龙:回复:chechezhu

姓朱也很好,朱字拆开来看就是“牛人”
madongfly:回z8913257:

人工智能是一个非常大的领域,包含了很多方向和分支。
而大学里的人工智能课通常都是该领域的入门课程,我不知道你所说的“真正的人工智能”指的是什么?不过这些入门的知识竟然会干扰你的思考,还真让我费解……
madongfly:回z8913257:

人工智能是一个非常大的领域,包含了很多方向和分支。
而大学里的人工智能课通常都是该领域的入门课程,我不知道你所说的“真正的人工智能”指的是什么?不过这些入门的知识竟然会干扰你的思考,还真让我费解……
文章分类
收藏
相册
其它图片
文章中的图片
我的大头贴
C++
Andrei Alexandrescu
Andrew Lumsdaine
Bjarne Stroustrup
boost
C++ Standard Commitee
Doug Gregor
Hans J. Boehm
Jaakko Jarvi
Jeremy G. Siek
Matthew Wilson
newsgroups
boost.Developer
boost.User
comp.lang.c++.moderated
comp.std.c++
TopLanguage
Open Source
Ant
codeplex
Danga
Google AJAX Search API
Google Code Prettify
Google Web Toolkit
Hadoop
MS shared source initiative
notepad++
STLSoft
不认识的朋友们
Delphij
fatalerror99
flow with the life
Glacier
jimaxsoft
lifesinger@淘宝UED
Mr. 6
realazy
Robbin
SpiritEpic
TK
wuyizi
Yelz
丁丁虫
冰云
刘慈欣
卢昌海
吴欣安(atppp)
周爱民
和菜头
姬十三
守望轩
小花@BlogBus
林达华
浦宇平
白鸦
程化
阮一峰
霍炬
飞之鸿
高远
鲍盛
机器学习/数据挖掘/信息检索/自然语言处理/认知科学/人工智能
AAAI
Apex
arXiv
Charles Kemp
Christopher Bishop
Christopher Manning
Cognitive Daily
Dan Jurafsky
David MacKay
ECML PKDD
Geoffrey Hinton
Herbert Simon
ICML
IJCAI
Jeff Hawkins
Jiawei Han
JMLR
Josh Tenenbaum
Larry Wasserman
Lucene
Marvin Minsky
MIT AI Lab
MIT Computational Cognitive Science Group
Mitchell Marcus
ML
NetLab
NIPS
Peter Norvig
Stanford AI Lab
Stanford NLP Lab
Stephen Boyd
Tom Mitchell
Trends in Cognitive Science
Vladimir Vapnik
Weka
Zhihua Zhou
技术
Coding Horror
High Scalability
Reddit
Stack Overflow
Steve Yegge
代码发芽网
淘宝UED团队
淘宝数据仓库团队
玩聚网
移山之道
其它
Gigapedia
Scientific American
Scientific American Mind
科学松鼠会
科幻世界
认识的朋友们
alai
chenyufei
dd
DreamHead
Googol
Jawley
Joyfire
littlestone
lxwde
Matrix67
realfun
RiceBall
roofalison
soloist
Tinyfool
windstorm
YongSun
书剑
云风
余晟
元凯宁
冯大辉(Fenng)
刘新宇
刘江@图灵
史晓明
吴新雨
周星星
周筠@博文视点
孟岩
张志强|阅微堂
张振
徐宥|4G Spaces
方舟@博文视点
曾登高
李笑来|Pure Pleasure
杨军
杨文博
熊节
王信文
王康生
范怀宇
荣耀
莫华枫
蒋涛
袁泳(g9)|负暄琐话
许式伟
谢东升
谷文栋|Beyond Search
邹欣@MSRA
郑昀
阿朱
陈冀康@华章
陈怀兴
鲍志云
存档
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

原创 为什么C++编译器不能支持对模板的分离式编译收藏

新一篇: 在C++中侦测内嵌型别的存在(rev#2) | 旧一篇: Enhanced Assertions

为什么C++编译器不能支持对模板的分离式编译

 

刘未鹏(pongba)

C++的罗浮宫(http://blog.csdn.net/pongba)

 

首先,一个编译单元translation unit是指一个.cpp文件以及它所#include的所有.h文件,.h文件里的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件(假定我们的平台是win32),后者拥有PEPortable Executablewindows可执行文件文件格式,并且本身包含的就已经是二进制码,但是不一定能够执行,因为并不保证其中一定有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(); //调用ff具有外部连接类型

}

 

在这个例子中,test. cppmain.cpp各自被编译成不同的.obj文件姑且命名为test.objmain.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 0xABCDEF这个地址可能是任意的,然而关键是这个地址上有一行指令来进行真正的call f动作。也就是说,这个.obj文件里面所有对f的调用都jmp向同一个地址,在后者那儿才真正”call”f。这样做的好处就是连接器修改地址时只要对后者的call XXX地址作改动就行了。但是,连接器是如何找到f的实际地址的呢在本例中这处于test.obj中),因为.obj.exe的格式是一样的,在这样的文件中有一个符号导入表和符号导出表import tableexport 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------//

template<class T>

void f(T t)