天天看點

C語言函數聲明以及函數原型

作者:C語言小新

C語言代碼由上到下依次執行,原則上函數定義要出現在函數調用之前,否則就會報錯。但在實際開發中,經常會在函數定義之前使用它們,這個時候就需要提前聲明。

所謂聲明(Declaration),就是告訴編譯器我要使用這個函數,你現在沒有找到它的定義不要緊,請不要報錯,稍後我會把定義補上。

函數聲明的格式非常簡單,相當于去掉函數定義中的函數體,并在最後加上分号;,如下所示:

dataType functionName( dataType1 param1, dataType2 param2 ... );

也可以不寫形參,隻寫資料類型:

dataType functionName( dataType1, dataType2 ... );

函數聲明給出了函數名、傳回值類型、參數清單(重點是參數類型)等與該函數有關的資訊,稱為函數原型(Function Prototype)。函數原型的作用是告訴編譯器與該函數有關的資訊,讓編譯器知道函數的存在,以及存在的形式,即使函數暫時沒有定義,編譯器也知道如何使用它。

有了函數聲明,函數定義就可以出現在任何地方了,甚至是其他檔案、靜态連結庫、動态連結庫等。

【執行個體1】定義一個函數 sum(),計算從 m 加到 n 的和,并将 sum() 的定義放到 main() 後面。

#include <stdio.h>

//函數聲明
int sum(int m, int n);  //也可以寫作int sum(int, int);

int main(){
    int begin = 5, end = 86;
    int result = sum(begin, end);
    printf("The sum from %d to %d is %d\n", begin, end, result);
    return 0;
}

//函數定義
int sum(int m, int n){
    int i, sum=0;
    for(i=m; i<=n; i++){
        sum+=i;
    }
    return sum;
}           

我們在 main() 函數中調用了 sum() 函數,編譯器在它前面雖然沒有發現函數定義,但是發現了函數聲明,這樣編譯器就知道函數怎麼使用了,至于函數體到底是什麼,暫時可以不用操心,後續再把函數體補上就行。

【執行個體2】定義兩個函數,計算1! + 2! + 3! + ... + (n-1)! + n!的和。

#include <stdio.h>

// 函數聲明部分
long factorial(int n);  //也可以寫作 long factorial(int);
long sum(long n);  //也可以寫作 long sum(long);

int main(){
    printf("1!+2!+...+9!+10! = %ld\n", sum(10));
    return 0;
}

//函數定義部分
//求階乘
long factorial(int n){
    int i;
    long result=1;
    for(i=1; i<=n; i++){
        result *= i;
    }
    return result;
}

// 求累加的和
long sum(long n){
    int i;
    long result = 0;
    for(i=1; i<=n; i++){
        result += factorial(i);
    }
    return result;
}           

運作結果:

1!+2!+...+9!+10! = 4037913

初學者編寫的代碼都比較簡單,頂多幾百行,完全可以放在一個源檔案中。對于單個源檔案的程式,通常是将函數定義放到 main() 的後面,将函數聲明放到 main() 的前面,這樣就使得代碼結構清晰明了,主次分明。

使用者往往隻關心函數的功能和函數的調用形式,很少關心函數的實作細節,将函數定義放在最後,就是盡量屏蔽不重要的資訊,凸顯關鍵的資訊。将函數聲明放到 main() 的前面,在定義函數時也不用關注它們的調用順序了,哪個函數先定義,哪個函數後定義,都無所謂了。

然而在實際開發中,往往都是幾千行、上萬行、百萬行的代碼,将這些代碼都放在一個源檔案中簡直是災難,不但檢索麻煩,而且打開檔案也很慢,是以必須将這些代碼分散到多個檔案中。對于多個檔案的程式,通常是将函數定義放到源檔案(.c檔案)中,将函數的聲明放到頭檔案(.h檔案)中,使用函數時引入對應的頭檔案就可以,編譯器會在連結階段找到函數體。

前面我們在使用 printf()、puts()、scanf() 等函數時引入了 stdio.h 頭檔案,很多初學者認為 stdio.h 中包含了函數定義(也就是函數體),隻要有了頭檔案就能運作,其實不然,頭檔案中包含的都是函數聲明,而不是函數定義,函數定義都放在了其它的源檔案中,這些源檔案已經提前編譯好了,并以動态連結庫或者靜态連結庫的形式存在,隻有頭檔案沒有系統庫的話,在連結階段就會報錯,程式根本不能運作。

關于編譯連結的原理,以及如果将代碼分散到多個檔案中,我們将在《C語言多檔案程式設計》專題中詳細講解。

除了函數,變量也有定義和聲明之分。實際開發過程中,變量定義需要放在源檔案(.c檔案)中,變量聲明需要放在頭檔案(.h檔案)中,在連結程式時會将它們對應起來,這些我們也将在《C語言多檔案程式設計》專題中詳細講解。

學完《C語言多檔案程式設計》,你對C語言的認識将會有質的提升,瞬間豁然開朗,輕松超越 90% 的C語言程式員。

函數參考手冊

最後再補充一點,函數原型給出了使用該函數的所有細節,當我們不知道如何使用某個函數時,需要查找的是它的原型,而不是它的定義,我們往往不關心它的實作。

www.cplusplus.com 是一個非常給力的網站,它提供了所有C語言标準函數的原型,并給出了詳細的介紹和使用示例,可以作為一部權威的參考手冊。

繼續閱讀