理解声明和定义

声明引入标识符并描述其类型,无论是类型,对象还是函数。声明是编译器接受对该标识符的引用所需的。这些是声明:

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 */