[英]Why does a declared prototype's function type not need to match the actual function's type?
我有一個使用功能function_1
的file1。 在使用file1編譯的file2中,我將該函數定義為int function_1(char a)
。 在我的file1中,我有原型行void function_1(char a)
。 當我進行編譯和測試時,一切正常,並且沒有任何警告。 為什么這樣可以? 為什么無論哪種方式都要求原型函數類型?
編輯:我很感謝警告,但只有默波芬嘗試回答所提出的問題,盡管我對回答不滿意。 如果鏈接器不檢查類型,為什么它甚至根本不應該成為聲明的一部分?
這是因為編譯器會針對給定的單個文件進行所有檢查,並且編譯結果僅包含對名稱function_1
的引用。 鏈接器不檢查任何類型,它僅連接名稱。
C使用類型有兩個目的:
所有這些一次完成一個編譯單元。 (編譯單元基本上是一個.c文件,其中包括所有標頭。)
您可以在不同的編譯單元中聲明不同類型的相同名稱。 (因為編譯器一次只考慮一個單元,所以不會捕獲該單元。)
但這意味着您有兩段代碼,對程序要處理的實體類型有不同的想法。 這會在運行時導致有趣和令人興奮的錯誤。 具體細節取決於您的平台/ ABI。
例如,在x86上, float
和int
具有相同的大小(4個字節)。 您可以定義一個功能
float foo(void) { return 42.0f; }
在文件A中並聲明為
int foo(void);
您可能希望生成的程序可以正常運行,只是它將重新解釋42.0f
的位模式為整數。 但這不是發生的情況:調用約定指定%eax
寄存器中返回int
,而float
使用%st0
浮點寄存器。 可能的結果是,A將把42.0f
放在%st0
而B將采用%eax
中的任何值作為foo
的返回值。
(這可能會以更有趣的方式出錯:例如float bar[] = { ... };
在一個文件中可以使用float bar[] = { ... };
在另一個文件中可以使用void bar(void);
在另一個文件中。這可能會導致第二個文件解釋內容浮點數組作為機器代碼(在調用bar()
時執行)。
這就是為什么編譯器需要知道參數的類型和返回值的原因:因此,它可以為函數調用生成正確的代碼(將參數放在函數期望的位置,並從函數放入的位置獲取返回值) 。
但是不幸的是,它不會交叉檢查多個文件中的聲明,而是依靠程序員來正確地執行它。 這就是為什么最佳實踐是在標頭文件中聲明“導出的”(或“公共”)函數(即未標記為static
函數),該標頭文件同時包含在定義函數的文件和這些函數的用戶中。 這樣,您無需手動聲明要調用的函數,並且無論如何都要進行聲明,任何類型的不匹配都將被視為無效/不兼容的重新聲明。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.