2016-06-09 64 views
1

我有以下代碼:除非出現提示,否則我的項目如何不抱怨未解決的未解決問題?

#include <iostream> 

extern "C" int calcSum_(int a, int b, int c); 

int main() 
{ 
    printf("Hello World"); 
    return 1; 
} 

爲什麼下面的代碼生成理所當然地認爲我在我的項目裏面他們calcSum_功能又無其他生活來源的文件嗎?它確實抱怨,當我嘗試做以下事情:

int result = calcSum_(1,2,3); 

不建設涉及創建一個可運行的可執行文件?這不涉及鏈接?它如何構建沒有錯誤?爲什麼我需要向鏈接器「突出顯示」該功能缺失?

+9

如果你永遠不會調用這個函數,爲什麼連接器還是要去找它呢? –

+3

呃,也許是因爲'calcSum_()!= calcSum()'(注意下劃線)? – paulsm4

+0

@ paulsm4我的不好。我編輯添加下劃線 – Bula

回答

2

傳統上講,鏈接器的工作很低級。目標文件包含導出符號的列表(以及它們的地址)以及缺失符號的列表(以及代碼中已解析地址必須替換的地址)。鏈接器必須將它們放在一起,在其他對象文件中找到缺失的符號並進行替換。

現在,如果編譯器看到函數原型但未使用它,則信息不會傳遞給鏈接器 - 目標文件不需要該符號,也不需要進行替換 - 因此鏈接器無法知道某個函數已被聲明但未被定義。順便說一下,這種行爲在一些C++ 03習慣用法中被積極利用 - 特別是「禁用拷貝構造函數」。您聲明瞭複製構造函數以禁用自動生成的複製構造函數,但是您沒有實現它,因此如果有人不小心嘗試使用它,則會發出鏈接錯誤。

+0

所以,如果我理解正確,如果有人試圖使用複製構造函數,那麼鏈接器會抱怨? (以防止意外使用拷貝構造函數? – Bula

+0

@Bula:雖然這是第二條保護線,但第一級將這種未實現的構造函數聲明爲private,這可以更好地反饋錯誤用法的位置;鏈接部分是爲了避免類本身的意外使用) –

+0

強制執行這樣的函數的任何方式?我假設一個檢查函數來調用並且不保存這些函數的返回? – Bula

0

在您提供的程序中,符號calcSum_從不被引用,所以它永遠不會被編譯器輸出到您的Object(.o.obj)文件中。該程序的唯一依賴項在功能printf(來自C標準運行時庫)

鏈接器運行時,它可以鏈接對象文件中的符號。 符號calcSum_不在目標文件中,因此鏈接程序不需要鏈接它,並且您有一個成功構建的可執行文件。

+0

也許很討厭問題,但是它開始計算從主函數開始鏈接到其返回值所需的符號? – Bula

0

行:

extern "C" int calcSum_(int a, int b, int c); 

告知一個函數存在的編譯器和如何調用它。沒有更多,沒有更多。

如果您調用該函數,則鏈接階段需要找到它。

在第一個示例中,沒有調用該函數,因此鏈接器不需要使用它。這是C++語言的好處之一,你不會爲你不使用的東西付費。

在第二個示例中,您調用該函數,因此它必須存在。

+0

我正在考慮Java接口,這些接口要求您實現其中定義的功能。所以如果我理解正確,鏈接只發生在你在代碼中調用的東西之間?你可以有20個未實現的函數?完全不同的一點是,如果函數沒有實現,你將如何強制執行錯誤? (即使不叫) – Bula

相關問題