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去尋找其定義的鑰匙。它只是為了給編譯器提供引用標識,讓編譯器能夠知道有這個引用,能用這個引用來引用某個實體。
宣告是為了讓編譯器正確處理對宣告變數和函式的引用。
定義是一個給變數分配記憶體的過程,或者是說明一個函式具體幹什麼用。