连接:http://www.cppblog.com/gujiayue/archive/2012/06/07/177916.aspx
虽然定义也是声明,但为了方便说明问题,下文中的声明只是单纯的声明,定义就只是定义。
1.声明、定义、初始化和赋值四个术语有着本质的不同,虽然有时候看起来差不多甚至完全一样,但如果不搞清楚很容易出现错误,或者错了不知道怎么改。2.四条规则
a: extern 关键词用来表明这是一个声明:extern int i; 变量 i 就是一个声明。声明前面一定要有一个关键字 extern,没有这个关键词就不是一个声明。
b: 没有 extern 就是一个定义,比如 int i=9; 是一个定义,特别要注意的是 int i; 这也是一个定义。
c: 初始化就是在变量定义时给变量一个初值,所以初始化语句也一定是一个定义语句,但反过来就不对了,因为类似于:int i;就是定义,但没有初始化。特别要注意的是:extern int i = 9;虽然有extern关键词,但是因为初始化了,所以这也是一个定义,不是声明。
(PS:这里比较特别,如果在头文件中写 extern int i = 9; {编译会有警告} 那么这个头文件就不能在其他地方被 include 了,否则会报错!切记)
3.extern关键词除了表明这是一个声明以外,更重要的是表明:所声明的变量的定义可能是在程序中其他文件里。如下代码
//file1.cpp
#include <iostream>
using namespace std;
extern int i;//这是一个声明,告诉编译器变量i的定义有可能是在其他源文件中,即使本文件中没有i的定义,你也不要报错。
void main() {
extern int i;//同样是对i的声明,作用与上面的声明完全一样,说明声明可以存在多个,实际上这两个声明只要任意一个就可以了。但是两个声明语句如果一个都没有,编译器就会认为变量i没有定义,会报错。
i=0;//赋值语句,给变量i一个新值,变量赋值前必须要已经定义了,如果不存在file2文件中的定义语句,虽然不会出现编译错误,但是链接会有错。
cout<<i;
}
//file2.cpp
int i;//首先是一个定义,而且是一个没有初始化的定义(不过实际上全局变量i被默认初始化为0),变量i被定义在file2源文件中
4.一个程序中可能包括不只一个文件,所有文件中同一个变量(其实主要说的全局变量)必须总共只能定义一次,但是声明可以有无数个。而且如果文件A中用到的变量的定义是在其他文件中,那么在
文件A中用这个变量之前,一定要加上一句extern声明语句,告诉编译器我所用的这个变量有可能是在其他文件里
5.extern int i=9;上面已经提到虽然有extern,但这也是一个定义,因为初始化了。 类似于这种有extern也有初始化的语句,只能出现在全局作用域,如果出现在函数内部,这是错误的。
6.转)有关编译器的一个特点: 现代编译器一般都属于按文件编译,就是说编译时多个源文件自己编译自己的,互不影响,好像只有自己一个文件。只要每个文件编译时没有出现错误,那么就不会发生编译时错误。但是 没有发生编译错误,并不代表程序就没有错误,因为还会发生链接错误。比如下面这两个代码
//A.cpp
int i;//这是变量i的定义
void main()
{
}
//B.cpp
int i;//这也是变量i的定义
编译时两个文件A和B是相互不影响的,所以编译时不会出现任何错误,但是这个程序是有问题的,因为全局变量i是被定义了两次的,所以链接时就会报告类似于下面的错误:
B.obj : error LNK2005: "int i" (?i@@3HA) already defined in A.obj
Debug/A.exe : fatal error LNK1169: one or more multiply defined symbols found
另外上面也提到了,编译时各个文件是相互不影响的,编译器是不会认为在这个文件中没有定义的变量其实很有可能人家是个全局变量,在其他文件中定义了,这就要报错。解决方法就是 用extern声明一个变量,告诉编译器人家这个变量不是没有定义,只是在其他文件中定义了,你别报错了。