本文將C語言的函數聲明在這裏做一總結。尤其注意同一工程中多個文件間函數調用和聲明的關係,很多C語言的教材上沒有涉及此話題。
1.目的:
函數聲明的目的是告訴編譯器被調用函數的返回值類型、參數個數及參數類型,以便編譯器檢查函數調用語句的合法性。
2.語法:
函數聲明的語法格式通常與函數定義的頭部是一致的,我們把函數定義的頭部拷貝下來,在後面加個分號就是函數聲明語句了。如果被調用函數是在另一個文件中定義的,可以在前面加一個extern,以表示是外部函數,也可以省略extern。
3.位置:
函數聲明既可以放在某個函數的內部,也可以放在所有函數的外面。如果放在函數內部,則被聲明函數只能在該函數內部被調用。如果放在所有函數的外面,則聲明後面的所有函數都能調用被聲明函數。通常的做法是:將所有函數的聲明統一放在所有函數的最前面。
4.函數聲明可以省略的兩種情況:
1) 被調用的函數定義在調用它的函數之前,這時被調用的函數可以不用聲明;
這是因爲編譯系統會先遇到被調用的函數定義,所以在調用之前已經知道該函數的返回值和參數類型。
2) 函數的返回值和參數類型都爲整型。
這是因爲,當省略函數聲明時,編譯系統會默認被調用的函數的返回值類型和參數類型是整型。
注意: 有些書上說當函數的返回值爲整型時,可以省略函數聲明。這種說法是不恰當的,在Dev C++平臺下測試,不僅返回值要爲整型,參數也要爲整型時,纔可以省略函數聲明,否則編譯會報錯“conflicting types for function_name”。比如一個函數的頭部這樣定義:int fun(float p),在省略函數聲明的情況下,編譯系統先遇到對函數fun的調用時,已經默認fun的返回值類型和參數類型是整型,但是當遇到該函數的定義時,發現函數的參數類型並不是整型,因此認爲是“衝突的類型”。
建議:對所有的函數都進行聲明,即使有時候可以省略。不要偷懶,這樣做比較安全。
5.多文件間的函數調用和聲明:
在一個工程中,多個文件分別包含了一些函數的定義,如果一個文件內的函數要調用另一個文件內的函數,也需要進行函數聲明。不過,情況和單個文件有所不同。我在Dev C++平臺下進行了實驗,創建了一個“console application”類型的C工程,除了默認的main.c,還添加了兩個程序文件file1.c和file2.c。
第一個實驗的代碼如下所示:
//file1.c 定義了一個函數fun1
float fun1(intp)
{
return 3.11*p;
}
//file2.c定義了一個函數fun2
float fun2(intp)
{
return 3.22*p;
}
//main.c 調用函數fun1和fun2
#include“stdio.h”
int main()
{
float r1,r2;
r1= fun1(); //錯誤的調用
r2= fun2(); //錯誤的調用
printf(" r1 = %f r2 =%f\n",r1,r2);
return 0;
}
第一個實驗我們沒有在main.c中對被調用函數fun1和fun2進行聲明,而且還寫了錯誤的函數調用語句(沒有傳遞參數)。對工程進行編譯,沒有報出任何錯誤,運行結果如下:
這個結果顯然是看不懂的。
注意 :如果上面三個文件的內容在同一個文件中,編譯時會報錯。
接下來 ,我們再做一個實驗:在main函數中增加對函數fun1和fun2的聲明,但是聲明是錯誤的,即和函數定義的頭部不一致。函數調用也是錯誤的,但是和聲明是一致的。修改後的main.c的定義如下:
//main.c 調用函數fun1和fun2
#include“stdio.h”
extern floatfun1(); //錯誤的聲明
externfloat fun2(); //錯誤的聲明
int main()
{
float r1,r2;
r1= fun1(); //錯誤的調用
r2= fun2(); //錯誤的調用
printf("r1 = %f r2 = %f\n",r1,r2);
return 0;
}
同樣,編譯時沒有報出任何錯誤,運行結果如下:
注意這個結果比較有意思,因爲沒有給fun1和fun2傳遞參數,函數省略了參數p,直接返回了3.11和3.22。
最後一個實驗,在main函數中使用正確的函數聲明,但是進行錯誤的函數調用。修改後的main.c的定義如下:
//main.c 調用函數fun1和fun2
#include“stdio.h”
extern floatfun1(int); //正確的聲明
externfloat fun2(int); //正確的聲明
int main()
{
float r1,r2;
r1= fun1(); //錯誤的調用
r2= fun2(); //錯誤的調用
printf("r1 = %f r2 = %f\n",r1,r2);
return 0;
}
這種情況下,編譯會報錯。
從以上的實驗中我們得出結論:同一工程中多個文件間存在函數調用時,應該進行函數聲明,並確保聲明是正確的。這樣就可以防止錯誤的函數調用和錯誤的運行結果。