2011-04-05 68 views
39

在什麼情況下GCC可以在而不是嘗試調用構成函數時拋出「未定義的引用」鏈接錯誤消息?GCC可以不抱怨未定義的引用嗎?

例如,在此C代碼被編譯和鏈接的GCC的情況:

void function() 
{ 
    made_up_function_name(); 
    return; 
} 

...即使made_up_function_name不存在任何地方代碼(不是頭,源文件,聲明或任何第三方庫)。

這樣的代碼可以在一定條件下被GCC接受和編譯,而不需要觸及實際的代碼?如果是這樣,哪個?

謝謝。

編輯:以前沒有任何聲明或提到made_up_function_name存在於其他地方。意思是整個文件系統的一個grep -R只有顯示確切的單行代碼。

+0

它可以(只要你編譯C,而不是C++)。你想完成什麼? – 2011-04-05 17:11:10

+0

我不想完成任何事情,它已經發生了,我想知道爲什麼可能。如果我使用「-g」並用文本編輯器編輯文件,made_up_function_name實際上存在於最終的鏈接二進制文件中。 – STenyaK 2011-04-05 17:17:27

+1

至於爲什麼,請參閱:http://stackoverflow.com/questions/4914589/c-prototype-functions/4914683,http://stackoverflow.com/questions/4800102/not-including-stdlib-h-does-not -produce-any-compiler-error/4800138#4800138,並且可能還有更多。 – 2011-04-05 17:20:20

回答

68

是的,可以避免報告未定義的參考 - 使用--unresolved-symbols鏈接器選項。

g++ mm.cpp -Wl,--unresolved-symbols=ignore-in-object-files 

man ld

--unresolved符號=方法

確定如何處理未解析的符號。存在用於方法4個 可能的值:

 ignore-all 
      Do not report any unresolved symbols. 

     report-all 
      Report all unresolved symbols. This is the default. 

     ignore-in-object-files 
      Report unresolved symbols that are contained in shared 
      libraries, but ignore them if they come from regular object 
      files. 

     ignore-in-shared-libs 
      Report unresolved symbols that come from regular object 
      files, but ignore them if they come from shared libraries. This 
      can be useful when creating a dynamic binary and it is known 
      that all the shared libraries that it should be referencing 
      are included on the linker's command line. 

自己共享庫的行爲還可以是 由受控 - [無糖]允許-SHLIB-未定義選項。

通常,鏈接器將爲每個 報告的未解決符號生成錯誤消息,但選項--warn-unresolved-symbols可以將 更改爲警告。

3

如果在使用函數之前聲明瞭函數的原型,它會阻止編譯。無論如何,鏈接時的錯誤仍然存​​在。

void made_up_function_name(); 
void function() 
{ 
    made_up_function_name(); 
    return; 
} 
+0

編輯的問題反映了這一點:除了示例中顯示的呼叫線之外,絕對沒有其他提及的組合功能。 – STenyaK 2011-04-05 17:19:02

1

如果function()不會被調用,它可能不包含在可執行文件,而不是搜索無論是從它調用的函數。

+0

所以它可能編譯即使沒有聲明原型,然後被鏈接呢?我認爲至少應該聲明原型,否則會產生解析錯誤,對嗎? – Heisenbug 2011-04-05 17:35:59

+0

@ 0verbose - 這取決於您使用哪個C標準。原本不需要原型。以後只有當你有除int以外的參數類型。 – 2011-04-05 17:59:15

0

然後這就是傳遞給GCC的-D標誌。

$cat undefined.c 
void function() 
{ 
    made_up_function_name(); 
    return; 
} 


int main(){ 
} 

$gcc undefined.c -Dmade_up_function_name=atexit 
$ 

想象一下尋找made_up_function_name的定義 - 它看起來沒有任何代碼中的「做事情」。 我想不出一個很好的理由在代碼中做這件事。

-D標誌是在編譯時更改代碼的強大工具。

+0

'-D'標誌在* compile *時間更改代碼。然後就有''Wl, - wrap'這樣的東西在鏈接時做。 – 2012-08-03 12:31:51

+0

如果將'-D'與預處理器令牌合併在一起,那麼文本'made_up_function_name'不需要在任何makefile或構建腳本中都顯示爲 - 例如。 – 2016-08-03 00:54:48

2

TL; DR可以不會抱怨,但你希望出現這種情況。如果您強制鏈接器忽略該問題,您的代碼將崩潰。這會起反作用。

您的代碼依賴於古代C(C99之前版本),允許在使用時隱式聲明函數。您的代碼是語義上等同於下面的代碼:

void function() 
{ 
    int made_up_function_name(...); // The implicit declaration 

    made_up_function_name(); // Call the function 
    return; 
} 

鏈接器理所當然地抱怨說,包含編譯function()目標文件是指未發現其他地方的象徵。您必須通過修復它,通過爲made_up_function_name()提供實施或通過刪除無意義呼叫。這就是它的全部。沒有鏈接器 - 擺弄。

0

POSIX鏈接器運行所遵循的「標準」算法使得代碼編譯和鏈接的可能性沒有任何錯誤。看到這裏的細節:https://stackoverflow.com/a/11894098/187690

爲了利用這種可能性包含目標文件的function(姑且稱之爲f.o)應該被放入庫中。該庫應該在編譯器(和/或鏈接器)的命令行中提及,但到那時,沒有其他目標文件(在前面提到的命令行中)應該已經調用了functionf.o中存在的任何其他函數。在這種情況下,鏈接器將無法從庫中檢索f.o。鏈接器將完全忽略f.o,完全忽略function,因此,完全忽略對made_up_function_name的呼叫。即使made_up_function_name沒有在任何地方定義,代碼將編譯。

1

當您使用鏈接器標記-r--relocatable構建時,它也不會產生任何「未定義的引用」鏈接錯誤消息。

這是因爲-r會鏈接新對象文件中的不同對象以在稍後階段鏈接。