有一个好方法可以避免大部分此类问题,这个方法只需要我们接受一个简单的规则:第个外部对象只在一个地方声明。这个声明的地方一般就在一个头文件中,需要用到该外部对象的所有模块都应该包括这个头文件。特别需要指出的是,定义该外部对象的模块也应该包括这个头文件。
例如,再来看前面讨论过的filename例子。这个例子可能是一个完整程序的一部分,该程序由多个模块组成,每个模块都需要知道一个特定文件名。我们希望能够做到只在一处改动这个特定的文件名,所有模块中的文件名就同时得到更新。我们可以这样做,创建一个文件,比如叫做file.h,它包含了声明。
extern char filename[];
需要用到外部对象filename的每个C源文件都应该加上这样一个语句:
#include “file.h”
最后,我们选择一个C源文件,在其中给出filename的初始值。我们不妨称这个文件为file.c:
#include “file.h” char filename[]=”/etc/passwd”;
注意,源文件file.c实际上包含filename的两个声明,这一点只要把include语句展开就可以看出:
extern char filename[]; char filename[] = “/etc/passwd”;
只要源文件file.c中filename的各个声明是一致的,而且这些声明中最多只有一个是filename的定义,这样写就是合法的。
让我们来看这样做的结果。头文件file.h中声明了filename的类型,因此每个包含file.h的模块也就自动地正确声明了filename的类型 。源文件file.c定义了filename,由于它也包含了file.h头文件,因此filename定义的类型自动地与声明的类型相符合。如果编译所有这些文件,filename的类型就肯定是正确的!