你提出的問題實際上是兩個問題,而不是一個問題。到目前為止,大多數回復都試圖用通用的毯子“這是K&R風格”來回答整個問題,而實際上只有一小部分與所謂的K&R風格有關(除非你以某種方式將整個C語言看作是“K&R風格”):
第一部分是函數中使用的奇怪語法。定義
int func(p, p2)void *p;int p2; /* <- optional in C89/90, but not in C99 */{
return 0;}
這是一個K&R型函數的定義。其他答案也很好地說明了這一點。其實也沒什么大不了的。語法不受歡迎,但即使在C99中仍然完全支持(C99中的“無隱式int”規則除外),這意味著在C99中您不能省略p2
).
第二部分與K&R風格無關。我指的是可以用“交換”參數調用函數,即在這樣的調用中不進行參數類型檢查。這與K&R風格的定義本身沒有什么關系,但它與您的功能沒有原型有關。您看,在C中,當您聲明這樣的函數時
int foo();
它實際上聲明了一個函數foo
這需要未知類型的未指定數目的參數..你可以稱之為
foo(2, 3);
和AS
j = foo(p, -3, "hello world");
ANS等等(你有這個想法);
只有帶有適當參數的調用才能“工作”(這意味著其他調用會產生未定義的行為),但完全由您來確保其正確性。即使編譯器以某種方式神奇地知道正確的參數類型及其總數,也不需要對不正確的參數進行診斷。
實際上,這種行為是特征C語言。一個危險的,但仍然是一個特征。它允許你做這樣的事情
void foo(int i);void bar(char *a, double b);void baz(void);int main(){
void (*fn[])() = { foo, bar, baz };
fn[0](5);
fn[1]("abc", 1.0);
fn[2]();}
也就是說,在沒有任何類型轉換的“多態”數組中混合不同的函數類型(不過,在這里不能使用各種函數類型)。同樣,這種技術的內在危險是顯而易見的(我不記得曾經使用過它,但我可以想象它在哪里是有用的),但這畢竟是C。
最后,將答案的第二部分與第一部分聯系起來的位。當你做一個K&R風格的函數定義時,它不會為這個函數引入一個原型。就函數類型而言,func
定義聲明func
如
int func();
也就是說,既不聲明參數的類型,也不聲明參數的總數。在您最初的帖子中,您會說“.它似乎指定了它使用了多少個參數.”。從形式上說,它不是!在你的雙參數K&R風格之后func
定義仍然可以調用func
如
func(1, 2, 3, 4, "Hi!");
也不會有任何違反約束的地方。(通常,高質量的編譯器會給您一個警告)。
另外,一個有時被忽視的事實是
int f(){
return 0;}
也是一個K&R風格的函數定義,不引入原型。要使它成為“現代”,你必須明確地指出void
在參數列表中
int f(void){
return 0;}
最后,與流行的觀點相反,在C99中完全支持K&R風格的函數定義和非原型函數聲明。如果我沒記錯的話,前者自C89/90以來就被否決了。C99要求在第一次使用之前聲明函數,但聲明不需要是原型。這種混淆顯然源于流行的術語混淆:許多人稱任何函數聲明為“原型”,而實際上“函數聲明”與“原型”并不相同。