问声明和定义全局变量和函数的最佳方法是什么?
答首先,虽然一个全局变量或函数可以有很多声明(并且在许多翻译单元中),但必须有且仅有一个定义。[脚注] 对于全局变量,定义是实际分配空间并提供初始化值的声明(如果有)。对于函数,定义是提供函数体的“声明”。例如,这些是声明
extern int i; extern int f();而这些是定义
int i = 0; int f() { return 1; }(实际上,关键字extern在函数声明中是可选的;请参见问题1.11。)
当您需要跨多个源文件共享变量或函数时,您当然希望确保所有定义和声明都一致。最佳的安排是将每个定义放在某个相关的 .c 文件中。然后,将外部声明放在一个头(“.h”)文件中,并在需要声明的地方包含它。包含定义的 .c 文件也应该包含相同的头文件,这样编译器就可以检查定义是否与声明匹配。#include它 wherever the declaration is needed. The.cfile containing the definition should also#includethe same header file, so the compiler can check that the definition matches the declarations.
此规则提高了可移植性:它符合 ANSI C 标准的要求,并且也与大多数 ANSI 之前的编译器和链接器兼容。(Unix 编译器和链接器通常使用“通用模型”,该模型允许多个定义,只要最多有一个被初始化;ANSI 标准将此行为作为“通用扩展”提及,无双关之意。一些非常老的系统可能曾经要求显式的初始化器来区分定义和外部声明。)
可以使用预处理器技巧来安排像这样的代码行
DEFINE(int, i);need only be entered once in one header file, and turned into a definition or a declaration depending on the setting of some macro, but it's not clear if this is worth the trouble, especially since it's usually a better idea to keep global variables to a minimum.
将全局声明放在头文件中不仅仅是个好主意:如果您希望编译器能够为您捕获不一致的声明,您必须将它们放在头文件中。特别是,切勿将外部函数的原型放在 .c 文件中——如果函数定义发生更改,很容易忘记更改原型,而不兼容的原型弊大于利。
参考:K&R1 Sec. 4.5 pp. 76-7
K&R2 Sec. 4.4 pp. 80-1
ISO Sec. 6.1.2.2, Sec. 6.7, Sec. 6.7.2, Sec. G.5.11
理由说明 第 3.1.2.2 节
H&S Sec. 4.8 pp. 101-104, Sec. 9.2.3 p. 267
CT&P Sec. 4.2 pp. 54-56