Declaration & definition
On the other hand, if an external variable is to be referred to before it is defined, or if it is defined in a different source file from the one where it is being used, then an extern declaration is mandatory.
It is important to distinguish between the declaration of an external variable and its definition. A declaration announces the properties of a variable (primarily its type); a definition also causes storage to be set aside. If
the lines
int sp;
double val[MAXVAL];
appear outside of any function, they define the external variables sp and val, cause storage to be set aside,and also serve as the declarations for the rest of that source file. On the other hand, the lines
extern int sp;
extern double val[];
declare for the rest of the source file that sp is an int and that val is a double array (whose size is determined elsewhere), but they do not create the variables or reserve storage for them.
There must be only one definition of an external variable among all the files that make up the source program;
other files may contain extern declarations to access it. (There may also be extern declarations in the file
containing the definition.) Array sizes must be specified with the definition, but are optional with an extern declaration.
Initialization of an external variable goes only with the definition.
Although it is not a likely organization for this program, the functions push and pop could be defined in one file, and the variables val and sp defined and initialized in another. Then these definitions and declarations
would be necessary to tie them together:
in file1:
extern int sp;
extern double val[];
void push(double f) { ... }
double pop(void) { ... }
in file2:
int sp = 0;
double val[MAXVAL];
Because the extern declarations in file1 lie ahead of and outside the function definitions, they apply to all
functions; one set of declarations suffices for all of file1. This same organization would also bee needed if the
definition of sp and val followed their use in one file.
另一方面,如果要在外部变量的定义之前使用该变量,或者外部变量的定义与变量的使
用不在同一个源文件中,则必须在相应的变量声明中强制性地使用关键字extern。
将外部变量的声明与定义严格区分开来很重要。变量声明用于说明变量的属性(主要是
变量的类型),而变量定义除此以外还将引起存储器的分配。如果将下列语句放在所有函数的外部:
int sp;
double val[MAXVAL];
那么这两条语句将定义外部变量sp与val,并为之分配存储单元,同时这两条语句还可以作
为该源文件中其余部分的声明。而下面的两行语句:
extern int sp;
extern double val[];
为源文件的其余部分声明了一个int 类型的外部变量sp 以及一个double 数组类型的外部变量val(该数组的长度在其它地方确定),但这两个声明并没有建立变量或为它们分配存储单元。
在一个源程序的所有源文件中,一个外部变量只能在某个文件中定义一次,而其它文件
可以通过extern 声明来访问它(定义外部变量的源文件中也可以包含对该外部变量的
extern 声明)。外部变量的定义中必须指定数组的长度,但extern 声明则不一定要指定数组的长度。
外部变量的初始化只能出现在其定义中。
假定函数push 与pop 定义在一个文件中,而变量val 与sp 在另一个文件中定义并被
初始化(通常不大可能这样组织程序),则需要通过下面这些定义与声明把这些函数和变量“绑定”在一起:
在文件file1 中:
extern int sp;
extern double val[];
void push(double f) { ... }
double pop(void) { ... }
在文件file2 中:
int sp = 0;
double val[MAXVAL];
由于文件file1 中的extern 声明不仅放在函数定义的外面,而且还放在它们的前面,因此它们适用于该文件中的所有函数。对于file1,这样一组声明就够了。如果要在同一个文件中先使用、后定义变量sp与val,也需要按照这种方式来组织文件。
From K&R Bible 4.4 scope rules