簡體   English   中英

為什么聲明的原型的函數類型不需要與實際函數的類型匹配?

[英]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使用類型有兩個目的:

  1. 用於一致性檢查(以防止程序員犯(一些)明顯的錯誤)
  2. 對於代碼生成(類型告訴編譯器要為變量保留多少內存,生成哪些代碼來訪問它們,等等)

所有這些一次完成一個編譯單元。 (編譯單元基本上是一個.c文件,其中包括所有標頭。)

您可以在不同的編譯單元中聲明不同類型的相同名稱。 (因為編譯器一次只考慮一個單元,所以不會捕獲該單元。)

但這意味着您有兩段代碼,對程序要處理的實體類型有不同的想法。 這會在運行時導致有趣和令人興奮的錯誤。 具體細節取決於您的平台/ ABI。

例如,在x86上, floatint具有相同的大小(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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM