2010-11-16 99 views
15

我無法理解以下行爲:一個標頭包含一些基本類型,另一個標頭中我在幾個函數中使用這些類型。之後,我開始根據自己定義的類型和功能構建類。在函數頭,如果我離開以下特徵:內聯函數鏈接

void whateverFunction(parameters) 

鏈接器指出,有whateverFunction的多個定義。現在,如果將其更改爲:

inline void whateverFunction(parameters) 

聯動問題消失了,所有的編譯和鏈接好。我知道的內聯函數是用它的代碼替代每個函數調用,而不是它非常黑暗,所以我的問題是:

鏈接器如何處理C++中的內聯函數?

+1

請參閱[「內聯的目的是什麼?」](http://stackoverflow.com/questions/3647053/what-is-are-the-purposes-of-inline)瞭解詳細信息尤其是* One Definition Rule *部分。 – 2010-11-16 11:41:36

回答

20

如果標題中的函數不是內聯的,則此函數的多個定義(例如,以多個轉換單位表示)違反了ODR規則。

內聯函數默認具有外部鏈接。因此,作爲ODR規則(下面給出),例如多個定義(例如,在多個翻譯單位)的結果是好的:

$ 6.4/5-「可以有一個類類型的多於一個 定義(第9節), 枚舉類型(7.2),內聯功能 與外部聯動 (7.1.2),類模板(第14), 非靜態函數模板(14.5.6)中, 靜態數據成員類別模板 (14.5.1.3),類別 模板(14.5.1.1)的成員函數或模板 專門化某些模板 參數未在程序中指定(14.7, 14.5.5),前提是每個定義都出現在不同的 轉換單元中,並且提供的 定義滿足以下 要求。鑑於這種命名d實體 在多於一個 翻譯單元,然後定義

- d中的每個定義應包括令牌的相同序列的 ;和[...]

鏈接器如何處理內聯函數是一個相當多的實現級別細節。只需知道該實現在ODR規則的限制範圍內接受這種多重定義

請注意,如果頭中的函數聲明更改爲「靜態內聯...」,那麼內聯函數明確地具有內部鏈接,並且每個翻譯單元都有自己的靜態內聯函數副本。

+0

*內聯函數默認具有外部鏈接。*:我覺得這個陳述有誤導性。內聯代碼根本不鏈接,至少不在函數名稱下。參見[Marcelo的答案](http://stackoverflow.com/a/4193657/772981)。 – Jarekczek 2012-11-30 13:32:45

+3

在現代編譯器上,可以將'inline'看作關鍵字,以允許多個定義而不是優化提示。編譯器可以決定不內聯內聯函數,並且鏈接器可以選擇編譯單元中的任何一個。程序員應該確保跨編譯單元的內聯函數是相同的。否則就會出現未定義的行爲。 – jdh8 2014-07-21 08:21:41

9

鏈接器可能根本看不到內聯函數。它們通常直接編譯到調用它們的代碼中(即代碼用於代替函數調用)。

如果編譯器選擇不內聯函數(因爲它只是一個提示),我不確定,但我認爲編譯器將它作爲一個普通的非內聯函數發出,並以某種方式註釋它,以便鏈接器只是選擇它看到的第一個副本並忽略其他副本。

0

內聯只是掩蓋了問題。有多個定義指出某個問題。

Juste要小心你如何使用你的標題。不要忘記: - < < #ifndef HEADER_NAME/#define HEADER_NAME/#endif >>避免多重包容。 - 不要使用間接包含:如果您在文件中使用類型,請添加相應的標題,即使同一文件中的另一個標題包含它也是如此。