[英]How important is function declaration?
當我瀏覽書籍和網站時,寫到函數聲明/原型是必須的,但是當我在不聲明的情況下運行程序時,它也會給我正確的結果。
你能解釋為什么嗎?
(我說的是函數的定義不在調用它的函數之前,因此函數定義不能提供有關原型的信息。如果不是這種情況,則聲明該函數不是強制性的,但是仍然被認為是一種好習慣,因為它不依賴於函數定義的順序,並且當一個順序改變時,它更不容易出錯。
函數聲明很重要,因為調用約定 (平台的ABI的一部分)可以根據函數返回並接受作為參數的類型為參數定義不同的位置並返回值。 例如,通常將返回(足夠大)結構的函數的返回值放在堆棧上,而返回int
函數通常使用CPU寄存器作為返回值。 沒有函數原型,大多數編譯器都假定函數返回int
,這可能是錯誤的。 考慮以下示例:
// in a separate implementation file
struct foo {
long long bar;
char buf[128];
};
struct foo function()
{
struct foo f = { 0 };
return f;
}
// in another file - the implementation is invisible here,
// and in the lack of a prototype, the compiler assumes an integer return value
int x = function();
現在這可能會使堆棧混亂,因為該函數將返回值壓入堆棧,但是賦值並不會彈出它,因為它采用了整數返回值。
在某種程度上,這取決於您的代碼符合哪個標准。 標准前編譯器非常松懈,因為它們根本不支持原型。 C89標准引入了原型,但是必須允許已經存在的大量代碼進行編譯。 因此,原型是可選的(從技術上講,對於諸如支持可變數量參數的printf()
函數除外;對於這些原型,即使在編譯器通常不會抱怨或引起麻煩的情況下,即使聲明是失蹤)。
對於C99(和C2011),應該在使用每個函數之前為每個函數創建一個原型聲明。 在定義每個非靜態函數之前,最好先使其具有一個可見的原型聲明。 該聲明應位於使用該函數的其他文件可以包含的標頭中。 標頭充當“裁判”; 它確保使用該函數的代碼具有正確的聲明信息,並且確保定義該函數的代碼與其他所有正在使用的聲明匹配。
通常,除非將編譯器推入嚴格模式,否則它將努力接受程序。 在GCC中添加-std=c99 -pedantic -Wall -Wextra
等選項將啟用許多警告。 值得在這些選項下干凈地編譯代碼。
如果您使用的是GCC,則可以添加警告更多選項,以確保您收到有關遺漏的通知。 根據GCC的版本,您可以使用:
-Wmissing-prototypes
(如果沒有原型,則警告您) -Wstrict-prototypes
(警告您非原型,例如extern int func();
) -Wold-style-declaration
(警告您有關“ old style”,K&R,非原型聲明的信息) -Wold-style-definition
(警告您有關“ old style”,K&R,非原型定義的信息) 我已經使用前兩個了很久了。 所有的GCC 4.x甚至3.x系列編譯器都支持它們。 后兩個我是在去年左右才遇到的。 GCC 4.7.x支持它們,但GCC 4.1.x不支持(4.5.1支持它們;這是我手邊的4.1.2以外的最舊的版本)。
GCC 4.7.x具有有用的選項: gcc --help=warnings
。 它以簡單的摘要列出了它支持的所有警告:
...
-Wmissing-prototypes Warn about global functions without prototypes
...
-Wold-style-declaration Warn for obsolescent usage in a declaration
-Wold-style-definition Warn if an old-style parameter definition is used
...
-Wstrict-prototypes Warn about unprototyped function declarations
...
使用函數聲明/原型是一種很好的做法/設計(不需要時)。
在很多情況下,您沒有選擇的余地,否則代碼將很難維護。
對於只有一個.c文件的程序,如果不使用原型,則必須按正確的順序將函數排序到.c文件中
=>函數的原型必須在您在代碼中使用函數描述之前聲明。
當您需要編寫更大的程序時,可以將代碼分成單獨的模塊。 每個模塊將具有“公開”和“私有”功能。 后者將被聲明為靜態(您仍然需要在.c文件頂部添加原型),並且'public'函數原型將放入.h文件中(標題)
只要函數實現位於函數調用之前,代碼就可以在沒有單獨的函數聲明的情況下運行,因為函數已由實現本身聲明。 通常,尤其是對於largre程序,應為任何函數聲明。
僅當在函數描述之前在代碼中使用該函數時,才必須聲明該函數的原型。
函數聲明對於使編譯器盡快檢測數據類型問題很有用。 如果創建一個需要float
的函數,而不是傳遞一個char
,則在某些情況下(例如,用於比較)它可能仍然可以工作,並且當您開始在其之上構建代碼時會中斷。 最后,計算機將所有內容都表示為一個位數組,因此您可以“求和”兩個字符或將包含\\0
兩個整數連接起來,就好像它們是字符串一樣,但是將來會使程序變得一團糟。
由於程序的編譯是從上到下(即第一行到最后一行)進行的,因此需要函數聲明(也稱為前向聲明)。
僅當函數調用在函數實現之前時才需要。
最好向編譯器提及在此聲明的函數已在程序中的某處使用。
聲明也可以在用戶定義的頭文件中完成。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.