理解宣告和定義

宣告引入識別符號並描述其型別,無論是型別,物件還是函式。宣告是編譯器接受對該識別符號的引用所需的。這些是宣告:

extern int bar;
extern int g(int, int);
double f(int, double); /* extern can be omitted for function declarations */
double h1();           /* declaration without prototype */
double h2();           /* ditto                         */

定義實際上例項化/實現此識別符號。這是連結器將引用連結到這些實體所需的內容。這些是與上述宣告相對應的定義:

int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
double h1(int a, int b) {return -1.5;}
double h2() {}  /* prototype is implied in definition, same as double h2(void) */

可以使用定義來代替宣告。

但是,它必須只定義一次。如果你忘記定義已在某處宣告和引用的內容,則連結器不知道將引用連結到哪些內容並抱怨丟失的符號。如果你多次定義某些內容,則連結器不知道將哪些定義連結引用並抱怨重複的符號。

例外:

extern int i = 0;  /* defines i */
extern int j;  /* declares j */

可以使用強符號與弱符號(從連結器的角度來看)的概念來解釋此異常。請看這裡 (幻燈片 22)以獲得更多解釋。

/* All are definitions. */
struct S { int a; int b; };             /* defines S */
struct X {                              /* defines X */
    int x;                              /* defines non-static data member x */
};
struct X anX;                                  /* defines anX */