2010-06-22 100 views
34

R函數聲明和ANSI函數聲明之間有什麼區別?函數聲明:K&R與ANSI

+1

你能舉出每種風格的例子嗎? – 2010-06-22 09:55:19

+2

一個相關的問題:http://stackoverflow.com/questions/1630631/what-is-useful-about-this-c-syntax – sharptooth 2010-06-22 10:00:30

+1

這是「K&R」,而不是「knr」(我已經解決了你的問題) ,它代表Kernighan和Ritchie,通常指的是他們在C大約1978年的開創性書籍C語言中描述的C語言*。本文可能對您有用:http://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C – 2010-06-22 10:01:06

回答

54

K & R語法已過時,除非必須維護非常舊的代碼,否則可以跳過它。

// K&R syntax 
int foo(a, p) 
    int a; 
    char *p; 
{ 
    return 0; 
} 

// ANSI syntax 
int foo(int a, char *p) 
{ 
    return 0; 
} 
+13

將K&R語法與void *類型結合使用是不合時宜的,因爲K&R C沒有*有*'void *'。 – caf 2010-06-22 12:13:49

+3

@caf不,我在使用非標準擴展語言:-) – Wizard 2010-06-22 12:46:19

+3

實際上,這是一個K&R函數定義,而不是K&R函數聲明。 – 2015-05-27 00:36:23

19

傳統ķ& R-樣式聲明/定義

當Kernighan和Ritchie首先出版的 「C程序設計語言」,C還不提供完整的函數原型。函數的前向聲明已存在,但其唯一目的是指示返回類型。對於返回int的函數,在C99之前不需要它們。

通過C89,還添加了函數原型的概念,該原型還指定了參數的類型(以及隱含地,它們的編號)。由於原型也是一種函數聲明,所以非官方術語「K & R函數聲明」有時用於不是原型的函數聲明。

// K&R declarations, we don't know whether these functions have parameters. 
int foo(); // this declaration not strictly necessary until C99, because it returns int 
float bar(); 

// Full prototypes, specifying the number and types of parameters 
int foo(int); 
float bar(int, float); 

// K&R definition of a function 
int foo(a) 
    int a; // parameter types were declared separately 
{ 
    // ... 
    return 0; 
} 

// Modern definition of a function 
float bar(int a, float b) 
{ 
    // ... 
    return 0.0; 
} 

意外的ķ& [R宣言

值得一提的是,新移民到C可能會意外地使用k & [R聲明時,他們打算使用一個完整的原型,因爲他們可能沒有意識到,一個空參數列表必須指定爲void

如果你聲明和定義函數,如

// Accidental K&R declaration 
int baz(); // May be called with any possible set of parameters 

// Definition 
int baz() // No actual parameters means undefined behavior if called with parameters. 
      // Missing "void" in the parameter list of a definition is undesirable but not 
      // strictly an error, no parameters in a definition does mean no parameters; 
      // still, it's better to be in the habit of consistently using "void" for empty 
      // parameter lists in C, so we don't forget when writing prototypes. 
{ 
    // ... 
    return 0; 
} 

...那麼你有沒有實際給予不帶任何參數的函數原型,但是以K & R-風格的函數的聲明接受未知類型的未知數量的參數。

this answer螞蟻註釋過類似的問題,這句法已被棄用,但仍合法的,因爲C99的(和函數指針的功能未知數量和參數類型仍然有潛在的應用前景,但在不確定的行爲高風險) ;因此,如果在沒有適當的原型的情況下聲明或調用某個函數,那麼兼容的編譯器至多會產生警告。

沒有原型的調用函數不太安全,因爲編譯器無法驗證您是否以正確的順序傳遞了正確數量和類型的參數;如果調用實際上不正確,則會導致未定義的行爲結果。

聲明和定義參數的功能,當然,正確的方法:

// Modern declaration of a parameterless function. 
int qux(void); // "void" as a parameter type means there are no parameters. 
       // Without using "void", this would be a K&R declaration. 

// Modern definition of a parameterless function 
int qux(void) 
{ 
    // ... 
    return 0; 
} 
+1

您需要澄清'C'的舊版本的含義。你說:_Older版本的C語言不需要完整的函數原型,但是在調用之前,仍然需要函數的前向聲明。但是C語言的早期版本(即預標準C語言)沒有原型,並且在調用之前不需要函數的前向聲明。即使C89/C90也不需要這種前向聲明。在使用前需要聲明功能(但仍不強制原型)的是C99。 – 2015-05-27 04:14:53

+0

@JonathanLeffler感謝提示,我已經閱讀了一些文章(主要是關於K&R時代C的維基百科文章)並進行了清理,現在我認爲它應該是歷史準確的。 – 2015-05-27 19:31:05

0

我只想補充一點,在傳統的K & [R風格類型修飾符對返回的int值AREN功能」甚至有必要。

考慮一個簡單的HelloWorld程序的現代C11註釋:

int main(int argc, char **argv) { 
    printf("hello world\n"); 
    return 0; 
} 

這等同於K & [R符號風格:

main(argc, argv) 
int argc; 
char **argv; 
{ 
printf("hello world\n"); 
return 0; 
} 

注意main()int被忽略,但代碼仍然編譯。這是K & R定義的一部分。

報價百科:

在C的早期版本中,僅當函數定義之前使用的返回需要被宣佈非int值的功能;如果使用其值,則假定沒有任何先前聲明的函數返回int類型。

--source:https://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C

這無疑是一個傳統的編碼風格,應該是由於清晰度的問題是可以避免的,但往往舊的算法教材青睞這種K個& [R風格。

+2

對於受虐狂,你可以有'main(argc,argv)char ** argv; {...}'作爲沒有顯式類型規範的參數類型,推斷爲'int'。另外,'function(a,b,c,d)char * d,double c,a; {...}「也很好;名稱不必按照它們出現在參數列表中的順序列在類型部分中。 – 2016-08-10 13:53:17