2010-04-08 103 views
34

如果我沒有理解它正確,這意味着函數的C++ extern關鍵字。爲什麼不包含頭文件?

extern void foo(); 

該函數foo是另一個翻譯單位申報。

1)爲什麼不只是#包括在這個函數聲明的頭?

2)如何鏈接器知道到哪裏尋找函數在鏈接的時間?

編輯:也許我應該澄清,上述聲明是隨後用

foo(); 

這是從來沒有在這個轉換單元中定義的功能。

回答

26

1)它可能沒有頭文件。但是,一般來說,對於大型項目,如果多個翻譯單元要使用該功能(不要重複自己),則應該有一個頭文件。

2)通過所有的目標文件和庫鏈接器搜索它講述了發現功能和其他符號。

+0

這是否意味着如果您知道函數的簽名,您可以調用模塊內部函數(讓我們假設源代碼不可用)? – user199421 2010-04-09 00:01:21

+1

如果功能有外部連接,那麼是的。但是,您將無法調用在未命名的命名空間中聲明的或聲明爲靜態的函數(除非您知道編譯器/鏈接器如何破壞名稱)。 – 2010-04-09 00:05:25

2

1)我不知道爲什麼我需要這個功能。也許別人可以介入。

2)鏈接器通過所有目標文件去和檢查每個對象文件中的符號決定了這一點。我假設取決於你的鏈接器,確切的搜索順序可能會有所不同。

對於GNU binutils的LD,含有缺失的符號對象之後出現在鏈接器命令行的所有目標文件和庫中搜索從左至右和第一發現符號被拾取。

實施例1:

  • AO - 使用FOO(),bar()的
  • 利巴 - 提供巴()
  • libb - 提供FOO()

$> ld ao -la -lb

將導致搜索未定義的符號。此後,ld將從左到右搜索這些符號,並在libb中找到liba和foo中的條。

這可能會導致在循環依賴奇怪的問題:

實施例2:

  • 一個。-O - 使用巴()
  • 利巴 - 提供杆(),使用FOO()
  • libb - 提供FOO(),使用巴()

現在,有一個循環依賴力霸和libb和鏈接之間會失敗:

$> LD AO香格里拉大-Lb

因爲通過在libb未定義的符號搜索時,勞工處會確定有沒有其他的LIB 到右邊 - lb,它提供了這個符號。這可以被固定在至少兩個方面:

1)鏈接力霸兩次: $> LD AO香格里拉大-lb香格里拉大

2)使用ld的分組功能 $> LD AO --start- group -la -lb --end-group

在情況2)中,該分組告訴ld搜索屬於該組的所有庫中的所有符號。

7

它已經意味着沒有extern關鍵字。除非您聲明它們是靜態的,否則默認情況下函數具有外部鏈接。

使用函數原型是可以的,但很容易出錯。當您重新定義函數實現時,您將得到的鏈接器錯誤並不容易診斷。鏈接器不知道在哪裏看,它的工作是給它一個包含函數定義的對象文件以保持它的快樂。

11

不,這意味着函數foo被聲明爲外部鏈接。外部鏈接意味着名稱foo在整個程序中引用相同的功能。功能定義在哪裏並不重要。它可以在此翻譯單元中定義。它可以在其他翻譯單位中定義。

使用extern關鍵字如您的示例中所示是多餘的。默認情況下,函數始終有外部鏈接。以上是相當於100%,剛剛

void foo(); 

至於鏈接,當鏈接器鏈接在一起的程序它只是看起來到處。它會查看所有定義,直至找到foo的定義。

10

正如其他人已經指出的那樣,extern關鍵字has用於表示名稱(變量或函數)具有外部鏈接,這意味着該名稱引用整個程序中的同一個對象。此外,這是在文件範圍定義的變量和函數的默認值,因此這種用法是多餘的。

還有一個使用extern關鍵字的說是這樣的:

extern "C" void foo(); 

這意味着功能foo將使用聯動的C約定(也許是因爲這是或在C庫定義的函數鏈接是一個旨在被C程序調用的函數)。

相關問題