声明引入一个标识符并描述其类型,可以是类型,对象或函数。声明是编译器需要接受对该标识符的引用的内容。这些是声明:
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 */
可以使用“强符号vs弱符号”的概念(从链接器的角度)来解释此异常。请查看此处(幻灯片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 */