青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-167  評(píng)論-8  文章-0  trackbacks-0

首先,一個(gè)編譯單元translation unit是指一個(gè).cpp文件以及它所#include的所有.h文件,.h文件里的代碼將會(huì)被擴(kuò)展到包含它的.cpp文件里,然后編譯器編譯該.cpp文件為一個(gè).obj文件(假定我們的平臺(tái)是win32),后者擁有PEPortable Executablewindows可執(zhí)行文件文件格式,并且本身包含的就已經(jīng)是二進(jìn)制碼,但是不一定能夠執(zhí)行,因?yàn)椴⒉槐WC其中一定有main函數(shù)。當(dāng)編譯器將一個(gè)工程里的所有.cpp文件以分離的方式編譯完畢后,再由連接器linker進(jìn)行連接成為一個(gè).exe文件。

 

舉個(gè)例子:

 1//---------------test.h-------------------//
 2void f();//這里聲明一個(gè)函數(shù)f
 3 
 4//---------------test.cpp--------------//
 5#include”test.h”
 6void f()
 7{
 8//do something
 9}
  //這里實(shí)現(xiàn)出test.h中聲明的f函數(shù)
10 
11//---------------main.cpp--------------//
12#include”test.h”
13int main()
14{
15f(); //調(diào)用f,f具有外部連接類型
16}

17

在這個(gè)例子中,test. cppmain.cpp各自被編譯成不同的.obj文件姑且命名為test.objmain.obj,在main.cpp中,調(diào)用了f函數(shù),然而當(dāng)編譯器編譯main.cpp時(shí),它所僅僅知道的只是main.cpp中所包含的test.h文件中的一個(gè)關(guān)于void f();的聲明,所以,編譯器將這里的f看作外部連接類型,即認(rèn)為它的函數(shù)實(shí)現(xiàn)代碼在另一個(gè).obj文件中,本例也就是test.obj,也就是說(shuō),main.obj中實(shí)際沒(méi)有關(guān)于f函數(shù)的哪怕一行二進(jìn)制代碼,而這些代碼實(shí)際存在于test.cpp所編譯成的test.obj中。在main.obj中對(duì)f的調(diào)用只會(huì)生成一行call指令,像這樣:

 

call f [C++中這個(gè)名字當(dāng)然是經(jīng)過(guò)mangling[處理]過(guò)的]

 

在編譯時(shí),這個(gè)call指令顯然是錯(cuò)誤的,因?yàn)?/span>main.obj中并無(wú)一行f的實(shí)現(xiàn)代碼。那怎么辦呢?這就是連接器的任務(wù),連接器負(fù)責(zé)在其它的.obj中(本例為test.obj尋找f的實(shí)現(xiàn)代碼,找到以后將call f這個(gè)指令的調(diào)用地址換成實(shí)際的f的函數(shù)進(jìn)入點(diǎn)地址。需要注意的是:連接器實(shí)際上將工程里的.obj“連接成了一個(gè).exe文件,而它最關(guān)鍵的任務(wù)就是上面說(shuō)的,尋找一個(gè)外部連接符號(hào)在另一個(gè).obj中的地址,然后替換原來(lái)的虛假地址。

 

這個(gè)過(guò)程如果說(shuō)的更深入就是:

 

call f這行指令其實(shí)并不是這樣的,它實(shí)際上是所謂的stub,也就是一個(gè)jmp 0xABCDEF這個(gè)地址可能是任意的,然而關(guān)鍵是這個(gè)地址上有一行指令來(lái)進(jìn)行真正的call f動(dòng)作。也就是說(shuō),這個(gè).obj文件里面所有對(duì)f的調(diào)用都jmp向同一個(gè)地址,在后者那兒才真正”call”f。這樣做的好處就是連接器修改地址時(shí)只要對(duì)后者的call XXX地址作改動(dòng)就行了。但是,連接器是如何找到f的實(shí)際地址的呢在本例中這處于test.obj中),因?yàn)?/span>.obj.exe的格式是一樣的,在這樣的文件中有一個(gè)符號(hào)導(dǎo)入表和符號(hào)導(dǎo)出表import tableexport table其中將所有符號(hào)和它們的地址關(guān)聯(lián)起來(lái)。這樣連接器只要在test.obj的符號(hào)導(dǎo)出表中尋找符號(hào)f當(dāng)然C++對(duì)f作了mangling的地址就行了,然后作一些偏移量處理后因?yàn)槭菍蓚€(gè).obj文件合并,當(dāng)然地址會(huì)有一定的偏移,這個(gè)連接器清楚寫(xiě)入main.obj中的符號(hào)導(dǎo)入表中f所占有的那一項(xiàng)即可。

 

這就是大概的過(guò)程。其中關(guān)鍵就是:

 

編譯main.cpp時(shí),編譯器不知道f的實(shí)現(xiàn),所以當(dāng)碰到對(duì)它的調(diào)用時(shí)只是給出一個(gè)指示,指示連接器應(yīng)該為它尋找f的實(shí)現(xiàn)體。這也就是說(shuō)main.obj中沒(méi)有關(guān)于f的任何一行二進(jìn)制代碼。

 

編譯test.cpp時(shí),編譯器找到了f的實(shí)現(xiàn)。于是乎f的實(shí)現(xiàn)二進(jìn)制代碼出現(xiàn)在test.obj里。

 

連接時(shí),連接器在test.obj中找到f的實(shí)現(xiàn)代碼二進(jìn)制的地址通過(guò)符號(hào)導(dǎo)出表。然后將main.obj中懸而未決的call XXX地址改成f實(shí)際的地址。完成。

 

然而,對(duì)于模板,你知道,模板函數(shù)的代碼其實(shí)并不能直接編譯成二進(jìn)制代碼,其中要有一個(gè)實(shí)例化的過(guò)程。舉個(gè)例子:

 

 1//----------main.cpp------//
 2template<class T>
 3void f(T t)
 4{}
 5 
 6int main()
 7{
 8//do something
 9f(10); // call f<int> 編譯器在這里決定給f一個(gè)f<int>的實(shí)例
10//do other thing
11}

12


也就是說(shuō),如果你在main.cpp文件中沒(méi)有調(diào)用過(guò)ff也就得不到實(shí)例化,從而main.obj中也就沒(méi)有關(guān)于f的任意一行二進(jìn)制代碼!如果你這樣調(diào)用了:

 

f(10); // f<int>得以實(shí)例化出來(lái)

f(10.0); // f<double>得以實(shí)例化出來(lái)

 

這樣main.obj中也就有了f<int>f<double>兩個(gè)函數(shù)的二進(jìn)制代碼段。以此類推。

 

然而實(shí)例化要求編譯器知道模板的定義,不是嗎?

 

看下面的例子(將模板的聲明和實(shí)現(xiàn)分離):

 

 1//-------------test.h----------------//
 2template<class T>
 3class A
 4{
 5public:
 6void f(); // 這里只是個(gè)聲明
 7}
;
 8 
 9//---------------test.cpp-------------//
10#include”test.h”
11template<class T>
12void A<T>::f()  // 模板的實(shí)現(xiàn)
13{
14  …//do something
15}

16 
17//---------------main.cpp---------------//
18#include”test.h”
19int main()
20{
21A<int> a;
22f(); // #1
23}

24

 

編譯器在#1處并不知道A<int>::f的定義,因?yàn)樗辉?/span>test.h里面,于是編譯器只好寄希望于連接器,希望它能夠在其他.obj里面找到A<int>::f的實(shí)例,在本例中就是test.obj,然而,后者中真有A<int>::f的二進(jìn)制代碼嗎?NO!!!因?yàn)?/span>C++標(biāo)準(zhǔn)明確表示,當(dāng)一個(gè)模板不被用到的時(shí)侯它就不該被實(shí)例化出來(lái)test.cpp中用到了A<int>::f了嗎?沒(méi)有!!所以實(shí)際上test.cpp編譯出來(lái)的test.obj文件中關(guān)于A::f一行二進(jìn)制代碼也沒(méi)有,于是連接器就傻眼了,只好給出一個(gè)連接錯(cuò)誤。但是,如果在test.cpp中寫(xiě)一個(gè)函數(shù),其中調(diào)用A<int>::f,則編譯器會(huì)將其實(shí)例化出來(lái),因?yàn)樵谶@個(gè)點(diǎn)上(test.cpp中),編譯器知道模板的定義,所以能夠?qū)嵗谑牵?/span>test.obj的符號(hào)導(dǎo)出表中就有了A<int>::f這個(gè)符號(hào)的地址,于是連接器就能夠完成任務(wù)。

 

關(guān)鍵是:在分離式編譯的環(huán)境下,編譯器編譯某一個(gè).cpp文件時(shí)并不知道另一個(gè).cpp文件的存在,也不會(huì)去查找當(dāng)遇到未決符號(hào)時(shí)它會(huì)寄希望于連接器。這種模式在沒(méi)有模板的情況下運(yùn)行良好,但遇到模板時(shí)就傻眼了,因?yàn)槟0鍍H在需要的時(shí)候才會(huì)實(shí)例化出來(lái),所以,當(dāng)編譯器只看到模板的聲明時(shí),它不能實(shí)例化該模板,只能創(chuàng)建一個(gè)具有外部連接的符號(hào)并期待連接器能夠?qū)⒎?hào)的地址決議出來(lái)。然而當(dāng)實(shí)現(xiàn)該模板的.cpp文件中沒(méi)有用到模板的實(shí)例時(shí),編譯器懶得去實(shí)例化,所以,整個(gè)工程的.obj中就找不到一行模板實(shí)例的二進(jìn)制代碼,于是連接器也黔驢技窮了。

因而,模板類的聲明與實(shí)現(xiàn)不能分開(kāi)寫(xiě)在cpp文件與h文件當(dāng)中,除非你#include  xxx.cpp文件。


posted on 2011-01-02 17:23 老馬驛站 閱讀(395) 評(píng)論(0)  編輯 收藏 引用 所屬分類: c++
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产亚洲精品aa| 午夜精品在线看| 亚洲视频电影在线| 欧美日一区二区三区在线观看国产免| a4yy欧美一区二区三区| 欧美一区二区三区四区夜夜大片| 国产丝袜美腿一区二区三区| 久久久久久有精品国产| 亚洲黄色在线| 午夜精品久久久久久久久久久| 国产亚洲一区二区三区在线观看| 欧美成在线观看| 久久国产日韩欧美| 久久亚洲精品一区| 日韩午夜剧场| 国产精品永久入口久久久| 久久精品免费电影| 亚洲精品日韩激情在线电影| 欧美一区二区精品久久911| 精品96久久久久久中文字幕无| 欧美精品久久久久久| 亚洲欧美一区二区激情| 欧美xxxx在线观看| 亚洲欧美日韩另类| 在线色欧美三级视频| 欧美视频在线播放| 久久在线免费观看| 亚洲欧美激情四射在线日| 亚洲缚视频在线观看| 欧美在线视频免费播放| av成人天堂| 1024日韩| 国产免费亚洲高清| 欧美日韩精品在线| 麻豆精品在线观看| 久久国产福利| 亚洲专区一区| 99国产精品久久久久久久| 欧美/亚洲一区| 久久av一区二区三区| 亚洲天堂av图片| 亚洲精品国产品国语在线app| 国产日韩欧美综合在线| 欧美午夜一区| 免费成人在线视频网站| 欧美在线视频播放| 亚洲一区在线播放| 在线亚洲精品福利网址导航| 欧美激情综合色| 女人色偷偷aa久久天堂| 久久精品国产亚洲一区二区三区| 亚洲欧美国产精品va在线观看| 99国产成+人+综合+亚洲欧美| 在线观看欧美成人| 激情偷拍久久| 国产主播一区二区三区| 国产视频久久久久久久| 国产精品青草久久| 国产精品视频xxxx| 国产精品日日做人人爱| 国产精品国产a| 欧美日韩精品久久| 欧美日韩国产精品成人| 欧美国产综合视频| 欧美精品一区二区高清在线观看| 麻豆成人综合网| 美女图片一区二区| 欧美成人精品在线视频| 欧美电影在线播放| 欧美黄色成人网| 欧美精品二区| 欧美日韩亚洲一区二区三区四区| 欧美人妖另类| 欧美午夜性色大片在线观看| 国产精品成人久久久久| 国产精品久久久久久久免费软件| 欧美午夜精品电影| 国产欧美欧美| 黄色成人小视频| 亚洲人成网站精品片在线观看| 亚洲人成啪啪网站| 亚洲视频福利| 欧美在线亚洲一区| 老司机精品视频网站| 亚洲成色777777女色窝| 亚洲区一区二| 亚洲在线观看视频| 久久精品免费观看| 蜜乳av另类精品一区二区| 欧美伦理影院| 国产乱码精品一区二区三区av| 国产在线不卡精品| 亚洲韩日在线| 亚洲一区免费看| 久久精品亚洲国产奇米99| 蜜桃av一区二区| 99精品国产在热久久下载| 亚洲欧美国产77777| 久久人人超碰| 欧美午夜在线一二页| 国产日韩亚洲欧美精品| 亚洲国产综合在线看不卡| 亚洲视频高清| 久久一二三国产| 亚洲全部视频| 欧美在线短视频| 欧美高清影院| 国产午夜精品全部视频播放| 亚洲欧洲日产国产网站| 亚洲欧美久久久久一区二区三区| 久久一区二区精品| 一区二区三区日韩精品视频| 久久久久成人精品| 国产精品v片在线观看不卡| 极品少妇一区二区三区精品视频| 亚洲视频一区二区| 免费亚洲电影在线| 亚洲综合另类| 欧美精品色综合| 国内精品亚洲| 午夜欧美视频| 日韩亚洲不卡在线| 久久久人成影片一区二区三区观看| 欧美日韩一区在线| 91久久精品美女高潮| 久久久久久噜噜噜久久久精品| 亚洲精品欧美激情| 麻豆成人小视频| 国内精品一区二区三区| 亚洲免费视频观看| 亚洲精品视频一区| 巨乳诱惑日韩免费av| 国产亚洲福利| 欧美在线播放视频| 亚洲视频网站在线观看| 欧美激情第一页xxx| 亚洲大片在线| 毛片一区二区| 欧美制服丝袜第一页| 国产精品久久久久永久免费观看| 日韩一本二本av| 亚洲电影免费观看高清完整版| 久久久久国产成人精品亚洲午夜| 国产精品自在线| 午夜精品久久久久久久久| 99国产精品国产精品久久| 欧美—级a级欧美特级ar全黄| 亚洲国产精品综合| 女人天堂亚洲aⅴ在线观看| 久久精品国产久精国产一老狼| 国产欧美激情| 久久成人精品视频| 亚洲专区在线视频| 国产精品视频大全| 欧美在现视频| 欧美伊久线香蕉线新在线| 国产亚洲欧美日韩一区二区| 久久国产高清| 欧美一区二区三区免费在线看| 国产视频久久久久久久| 久久福利视频导航| 久久成年人视频| 精品99一区二区| 欧美成人亚洲成人日韩成人| 免费成人小视频| 一本色道久久综合一区 | 亚洲视频在线观看视频| 欧美日韩第一区| 午夜精品视频一区| 欧美亚洲在线视频| 狠狠色综合网| 亚洲国产激情| 欧美视频福利| 久久精品欧洲| 免费看成人av| 亚洲一级片在线观看| 亚洲欧美成人网| 在线日韩av片| 日韩一二在线观看| 国产精品青草久久| 久久综合一区| 欧美另类女人| 久久精品女人| 你懂的一区二区| 午夜精品久久久久久| 欧美中文在线免费| 亚洲精品一区在线观看| 一区二区三区四区蜜桃| 国产日韩欧美在线视频观看| 欧美成人精品一区二区三区| 欧美日韩dvd在线观看| 久久国产一区二区三区| 免费国产自线拍一欧美视频| 亚洲一区二区精品视频| 欧美在线观看视频一区二区| 日韩午夜精品| 久久大综合网| 中日韩在线视频| 久久九九全国免费精品观看| 夜夜爽夜夜爽精品视频|