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