C中有兩種指定參數(shù)的方法,一種是使用標(biāo)識(shí)符列表,另一種是使用參數(shù)類型列表??梢允÷詷?biāo)識(shí)符列表,但類型列表不能。因此,要說一個(gè)函數(shù)在函數(shù)定義中不接受參數(shù),您可以使用一個(gè)(省略的)標(biāo)識(shí)符列表來完成此操作。
void f() {
/* do something ... */}
它有一個(gè)參數(shù)類型列表:
void f(void) {
/* do something ... */}
如果在參數(shù)類型列表中,只有一個(gè)參數(shù)類型是無效的(它必須沒有名稱),那么這意味著函數(shù)沒有參數(shù)。但這兩種定義函數(shù)的方法在聲明什么方面有差異。
標(biāo)識(shí)符列表
第一個(gè)定義函數(shù)接受特定數(shù)量的參數(shù),但既沒有傳遞計(jì)數(shù),也沒有傳遞所需內(nèi)容的類型-就像使用標(biāo)識(shí)符列表的所有函數(shù)聲明一樣。所以打電話的人必須事先準(zhǔn)確地知道類型和計(jì)數(shù)。因此,如果調(diào)用者調(diào)用給它一些參數(shù)的函數(shù),則行為是未定義的。例如,堆??赡軙?huì)損壞,因?yàn)楸徽{(diào)用的函數(shù)在獲得控制時(shí)需要不同的布局。
不建議在函數(shù)參數(shù)中使用標(biāo)識(shí)符列表。它在過去使用過,現(xiàn)在仍然存在于許多生產(chǎn)代碼中。由于這些參數(shù)提升,它們可能造成嚴(yán)重的危險(xiǎn)(如果提升參數(shù)類型與函數(shù)定義的參數(shù)類型不匹配,行為也是未定義的!)當(dāng)然也不太安全。所以,請(qǐng)始終使用void
對(duì)于沒有參數(shù)的函數(shù),只有在聲明和函數(shù)的定義中。
參數(shù)類型表
第二個(gè)函數(shù)定義為零參數(shù),并與所有使用參數(shù)類型列表(稱為參數(shù)類型列表)聲明函數(shù)的情況進(jìn)行通信。prototype
..如果調(diào)用者調(diào)用該函數(shù)并給它提供一些參數(shù),這就是一個(gè)錯(cuò)誤,編譯器將產(chǎn)生一個(gè)適當(dāng)?shù)腻e(cuò)誤。
第二種聲明函數(shù)的方法有很多好處。當(dāng)然,其中之一是檢查參數(shù)的數(shù)量和類型。另一個(gè)不同之處在于,因?yàn)榫幾g器知道參數(shù)類型,所以它可以將參數(shù)的隱式轉(zhuǎn)換應(yīng)用到參數(shù)的類型。如果不存在參數(shù)類型列表,則不能這樣做,并且參數(shù)被轉(zhuǎn)換為提升類型(這稱為默認(rèn)的參數(shù)提升)。char
會(huì)變成int
,例如,float
會(huì)變成double
.
函數(shù)的復(fù)合類型
順便說一句,如果一個(gè)文件同時(shí)包含一個(gè)省略的標(biāo)識(shí)符列表和一個(gè)參數(shù)類型列表,那么參數(shù)類型列表“獲勝”。函數(shù)末尾的類型包含一個(gè)原型:
void f();void f(int a) {
printf("%d", a);}// f has now a prototype.
這是因?yàn)檫@兩項(xiàng)聲明沒有任何矛盾之處。然而,第二個(gè)國(guó)家還有話要說。那就是有一個(gè)論點(diǎn)被接受了。同樣的情況也可以反向進(jìn)行。
void f(a)
int a;{
printf("%d", a);}void f(int);
前者使用標(biāo)識(shí)符列表定義函數(shù),而第二個(gè)則使用包含參數(shù)類型列表的聲明為其提供原型。