2013-01-09 13 views
5

關於ANSI C函數聲明,這是如何改進舊的K & R風格?我知道他們之間的差異,我只是想知道使用舊風格會產生什麼問題,以及新風格如何改進。ANSI C函數如何聲明對舊Kernigan和Ritchie風格的改進?

+1

我看到有一個投票來關閉它。我同意這個問題可能是模糊的,但我相信有一個具體的答案(見我的)。 –

回答

8

舊式函數聲明,特別是不允許編譯時檢查調用。

例如:

int func(x, y) 
char *x; 
double y; 
{ 
    /* ... */ 
} 

...

func(10, 20); 

當編譯器看到的號召,它不知道該類型的功能func的參數,所以它可以」 t診斷錯誤。

相比之下:

int better_func(char *x, double y) { 
    /* ... */ 
} 

...

better_func(10, 20); 

將導致編譯錯誤信息(或至少一個警告)。

另一個改進:原型使得有可能具有的功能與float類型的參數,以及比int窄整數類型(3種char類型和兩個short類型)的。沒有原型,float被提升爲double,窄整數類型被提升爲intunsigned int。使用原型,float參數作爲float傳遞(除非函數是可變參數,如printf,在這種情況下舊規則適用於可變參數)。

C Rationale文件討論這部分6.7.5.3,可能比我更好:

的函數原型機制是最有益的補充 C語言之一。當然,這個功能在過去25年的Algol派生語言的許多 中都有先例。標準中採用的特殊形式 大部分基於C++。

函數原型提供了強大的轉換時間錯誤 檢測能力。在沒有原型的傳統C實踐中,翻譯器在調用另一個 源文件中聲明的函數時檢測錯誤(錯誤的 參數數量或類型)非常困難。在運行時間 或通過使用輔助軟件工具發現此類錯誤的檢測。

在函數中的函數原型的範圍不調用,整數 參數具有施加的整數促銷和浮子 參數被加寬以。在這樣的電話 中不可能通過未轉換的charfloat參數。函數 原型使程序員可以顯式控制參數類型轉換,因此通常不合適的和有時效率低下的自變量缺省擴展規則可能會被實現所抑制,例如 。

還有更多;去閱讀它。

+0

有趣的是,K&R風格更符合C聲明的基本思想; 「聲明模仿使用」。 – bames53

+1

爲什麼編譯器檢測不到K&R式函數的類型不匹配?所有的類型信息仍然存在。 – templatetypedef

+2

@templatetypedef:不一定。舊式非原型函數*聲明*不包含函數的主體,因此它不提供參數類型信息。例如:'some_header.h'中的'int func();'。完整的*定義*確實提供了這些信息,但是(a)它可能不在同一個源文件中,並且(b)編譯器不需要使用它,即使它是。使用無效參數調用非原型函數具有未定義的行爲;它不需要被診斷。 –

3

以K & R A非限定函數聲明看起來如下

int foo(); 

,並介紹接受未指定數目的參數的函數。這種聲明風格的問題很明顯:它既沒有指定參數的數量,也沒有指定它們的類型。編譯器沒有辦法根據調用點處的參數數量或類型來檢查調用的正確性。在參數類型與預期參數類型不匹配的情況下,編譯器無法執行參數類型轉換或問題和錯誤消息。

函數聲明,其被用作的功能定義以K &一個部分R看起來如下

int foo(a, b) 
int a; 
char b; 
{ ... 

它指定的參數的數量,但仍沒有指定其類型。此外,即使參數的數量似乎通過此聲明公開,它仍然正式聲明foo的方式與int foo();的方式相同,這意味着將其稱爲foo(1, 2, 3, 4, 5)仍然不構成約束違規。

新樣式,即帶原型的聲明比較好,原因很明顯:它公開了參數的數量和類型。它強制編譯器檢查調用的有效性(關於參數的數量和類型)。它允許編譯器執行從參數類型到參數類型的隱式類型轉換。

原型聲明提供了其他一些不太明顯的好處。由於函數參數的數量和類型對調用者和函數本身都是精確已知的,因此可以選擇在調用點傳遞參數(調用約定)的最有效的方法,而不必查看函數定義。如果沒有這些信息,所有功能都必須遵循一個預定義的「一刀切」調用約定。