函式宣告的發展
1 隱式函式宣告 implicit function declaration main 函數和 printf 函數傳回值類型為 int, 若不聲明, 編譯器預設函數傳回值為 int 類型 C90標準起,這種寫法就步入了被逐步拋棄的過程(儘管當時還沒有完全立即廢止) C99廢除了隱式函式宣告法則(remove implicit function declaration), 省略main()前面的int也已經不再容許了
main(){ printf("hello, world!\n");}
2 函數型別宣告 function type declaration sqrt 函數類型不是 int, 需要進行函數類型說明(只聲明函數類型和函數名) 調用函數時存在參數類型或個數方面的錯誤編譯器是無法察覺的
double sqrt();int main(){ printf("%f\n" , sqrt(9.));}
3 函數定義聲明 把函數定義寫在函數調用之前, 這種聲明可以檢查出函數調用時在參數個數和類型方面的錯誤 弊端是在由多個源檔案組成的來源程式時, 不利於代碼的組織 函數定義聲明屬於函數原型聲明
double square(double x){ return x * x ;}int main(void){ printf("%f\n" , square(3.) ); return 0;}
4 函數原型聲明 function propotype
C 標準借鑒 C++ 語言規定了函數原型(Function Propotype)聲明, 不但可以檢查函數調用時參數類型和個數方面的錯誤,同時解決了原始碼的組織問題
double square (double x);int main(void){ printf("%f\n" , square(3.) ); return 0;}double square ( double x){ return x * x ;}
總結
函數型別宣告, 函數定義, 函數原型都是函式宣告 聲明 declaration
指定標識符的意義和性質
A declaration specifies the interpretation and attributes of a set of identifiers. 定義 definition
某個標識符的定義(Definition)同時也是這個標識符的聲明(Declaration), 函數定義則包括函數體
A definition of an identifier is a declaration for that identifier that: ……for a function, includes the function body 原型 propotype
特指包括說明參數類型的函式宣告,它同樣包含用這種方式寫出的函數定義 錯誤辨析 錯誤原文
譚浩強 ,《C程式設計》(第四版),清華大學出版社,2010年6月,p182
函數的定義是指對函數功能的確立,包括指定函數名,函數實值型別、形參及其類型以及函數體等,它是一個完整的、獨立的函數單位。
函數的聲明的作用則是把函數的名字,函數類型以及形參的類型、個數和順序通知編譯系統,以便在調用該函數時進行對照檢查(例如,函數名是否正確,實參與形參的類型和個數是否一致),它不包括函數體。 分析
“對函數的定義和聲明不是一回事”是錯誤的, 函數定義本身就是一種函式宣告, 是子集關係。
“而函數的聲明的作用則是把函數的名字,函數類型以及形參的類型、個數和順序通知編譯系統,以便在調用該函數時進行對照檢查,它不包括函數體”這句話同樣不通。函數定義本身就是一種函式宣告,所以無法斷定函數的聲明是否包括函數體;而且老式的函數型別宣告也屬於函式宣告,這種函式宣告並不檢查參數類型及個數方面的錯誤。此外函式宣告也並沒有檢查“函數名”正確與否的功能。這段文字中的“函數類型”這個概念也有錯誤,函數類型所描述的不但包括函數傳回值類型,也可能一併描述參數的個數和類型(如果是函數原型),因此不能與“形參的類型、個數”相提並論。 函式宣告的作用 被調函數根據函數類型將函數傳回值存入棧或寄存器中, 調用函數將根據函數原型提供的類型訪問這個記憶體或寄存器位置 c++ primer plus p204 調用函數根據函數原型提供的參數類型, 傳入確定類型和數量的實參, 使被調函數能夠正確處理傳入的參數 參考
“函式宣告”、“函數原型”與“函數定義”辨析