c語言的定義與宣告

Sike發表於2019-05-13

c語言的定義與宣告

宣告

很多人都不太明白宣告這玩意有什麼用。

  • 我定義一個變數:
    1.分配了記憶體

2.初始化了資料
3.以後可以存取

  • 但是宣告這玩意,好像什麼也沒幹哪!

宣告(declaration )指定了一個變數的識別符號,用來描述變數的型別,是型別還是物件,或者函式等。宣告,用於編譯器(compiler)識別變數名所引用的實體。以下這些就是宣告:

  • extern int bar;

  • extern int g(int, int);

  • double f(int, double); // 對於函式宣告,extern關鍵字是可以省略的。

  • class foo; // 類的宣告,前面是不能加class的。

要理解宣告,就得了解聯結器(linker).我們知道c語言是分開編譯。

gcc -c 1.c 2.c 3.c

c編譯器會輸出1.o 2.o 3.o

注意
編譯器根本不知道3者之間的關係:

  • 1.c中是否呼叫了2.c中定義的函式f()

  • 2.c是否修改了3.c中定義的變數var

注意編譯器壓根不知道這麼複雜的鄰里關係,七舅姥爺的遠親表姨。

舉個例子:

1.c


int main(){
    f();
    return 0;
}

gcc -c 1.c

報錯defined refernece to f

但是你加上

extern void f();

int main(){
    f();
    return 0;
}

就OK了,編譯就通過!
宣告就是告訴編譯器,我這個是使用別人的,你別報錯!到時候聯結器會幫我找到的。

gcc 1.c 2.c 3.c

聯結器負責在其他兩個模組裡找f的定義

定義

定義是對宣告的實現或者例項化。
聯結器(linker)需要它(定義)來引用記憶體實體。
與上面的宣告相應的定義如下:

  • int bar;

  • int g(int lhs, int rhs) {return lhs*rhs;}

  • double f(int i, double d) {return i+d;}

  • class foo {};// foo 這裡已經擁有自己的記憶體了,對照上面兩個函式,你就應該明白{}的用處了吧?

注意
定義只能使用一次!
如果你定義變數超過一次,聯結器是不知道把reference和哪塊記憶體連線,然後就會報 duplicated symbols這樣的錯誤了(symbols是指定義後的變數名)。

總結

總之,最終原因是c採用分開編譯,最終連線的方式。
所以宣告就成為linker去尋找其定義的鑰匙。它只是為了給編譯器提供引用標識,讓編譯器能夠知道有這個引用,能用這個引用來引用某個實體。

宣告是為了讓編譯器正確處理對宣告變數和函式的引用。
定義是一個給變數分配記憶體的過程,或者是說明一個函式具體幹什麼用。

相關文章