2011-09-28 34 views
1

例:爲什麼編譯器不能自動內聯自由定義的函數?相反,導致鏈接錯誤

// header.h 
void foo() // function definition in the file 
{ 
} 

// file1.cpp 
#include"header.h" 
... 

// file2.cpp 
#include"header.h" 
... 

上面的代碼將導致連接錯誤。假設如果編譯器自動生成inline foo()那麼就不會有鏈接器錯誤。

我的問題是從語言的角度來看。爲什麼編譯器不會自動創建它inline?它會有所作爲嗎?

問題換句話說:「如果編譯器在每個定義的自由函數前面假定爲inline,可能會發生什麼?」

回答

6

標題只被視爲標題文本的複製粘貼。編譯器不知道你的代碼是在一個頭文件而不是一個源文件中,所以它必須同時處理,以便發生錯誤。該語言指定了這一點。

+0

如何在每個免費函數前假設關鍵字「inline」的編譯器? – iammilind

+5

@iammilind然後,當你偶然有兩個(不同的)具有相同名字的函數時,你會得到不一致/不正確的行爲(而不是錯誤)。只是不要將定義放入標題(無論如何都是組織的良好做法)並添加包含警衛(每個標題爲三行)。 – delnan

1

那麼,答案是,基本上,C++標準要求它的行爲如此,所以它的確如此。這是One Definition Rule的一部分。

實際上,編譯器必須生成鏈接器可見的函數,以防在其他地方實際使用它。例如,下面的file3.cpp必須工作:

void foo(); 
void call_foo() { 
    foo(); 
} 

,爲了爲工作,爲foo()生成的代碼必須是可用的連接器。編譯器一次只查看一個翻譯單元(.cpp文件及其中包含的所有內容),因此無法知道它實際上是否生成了兩次。所以它確實如此。然後鏈接器捕獲它。

0

可以inline它(但如果它不是static它仍然需要單獨的功能),但你錯過了這一點。

編譯器發現你用相同的簽名定義了兩次函數。他們可能會有所不同。所以在鏈接階段,它會產生一個錯誤,讓你知道發生了一些不好的事情。

聲明在頭void foo();,並實現在cpp文件的一個功能。

+0

這不是編譯時錯誤,而是鏈接時錯誤。這兩個源文件都會編譯得很好。 –

+0

對不起,措辭不妙。 –

1

這不會導致鏈接器錯誤。它可能導致鏈接器錯誤,但編譯器不需要捕獲該錯誤。

跨模塊一致性完全是程序員的責任。 C++編譯器不需要能夠看到例如您在具有不同類定義的兩個不相關文件中使用相同的類名。無論發生什麼,這都是你的錯。

一般而言,C++編譯模型的許多顯然奇怪的缺點都與它必須能夠通過一次只查看一個模塊(編譯單元)來編譯C++程序有關。需要確保編譯時間和空間對於大型項目不會爆炸。

0

問題自動在鏈接時間內聯,給定C如何定義,是否存在兩個具有相同名稱的不同函數。底層的二進制接口不會維護必要的元數據來解決這種衝突。拋出第三個源文件,它使用(但沒有定義自己)具有這樣一個名稱的函數,並且它不知道應該使用哪一個。

我懷疑可能有一些實驗C(或更可能是C類)編譯器在那裏做這件事,但它們幾乎保證以某種方式破壞兼容性。

相關問題