1.什么是转换单元
程序中的每个.cpp文件和它包含的所有头文件称为一个转换单元。
编译器处理每个转换单元,生成二进制对象文件,用扩展名.obj来标识。
链接器将对象文件组合起来,生成一个可执行文件,用扩展名.exe来标识。
2.作用域
使用{}来限定变量的作用域
内部作用域可以定义一个和外部作用域相同的名称,此时,内部作用域中定义的名称,将隐藏外部作用域中的名称,
若要访问外层作用域中的名称,可使用解析运算符::,解析运算符的介绍,可参考 C++范围解析运算符::的使用
int main() { const int limit =10; std::cout<<"limit 1 is "<<limit<<std::endl; { const int limit = 5; std::cout<<"limit 2 is "<<limit<<std::endl; std::cout<<"limit 3 is "<<::limit<<std::endl; } std::cout<<"limit 4 is "<<limit<std::endl; }
输出结果:
limit 1 is 10
limit 2 is 5
limit 3 is 10
limit 4 is 10
3.转换单元的全局名称属性linkage
每个转换单元中的全局名称,都有一个属性linkage,该属性指明该全局名称可以在程序代码的什么地方使用。
内部链接属性:该名称只能在同一转换单元的任何地方访问。比如全局const变量。
外部链接属性:该名称除了在同一转换单元访问外,还可在其他的转换单元中访问。除了全局const变量,其他的全局名称都是外部链接属性的。
局部名称没有链接属性。
4.什么是“一个定义”规则
在所有的转换单元中,外部链接属性的全局名称,如变量、函数、类类型、枚举类型、模板都只能定义一次。
内联函数除外,内联函数的定义必须出现在调用该函数的每个转换单元中。
内部链接属性的名称可以在多个转换单元中同时定义。
5.如何访问另一转换单元中定义的变量
对于函数来说,如果函数的调用和定义不在同一个转换单元,编译器会把这个函数调用标记为外部的,让链接程序去处理它。
对于变量来说,是不同的。必须使用extern关键字来声明该变量。表示该变量的定义在另一个转换单元中。
示例代码如下:
myextern.cpp int limit = 15; mymain.cpp int main() { extern int limit; std::cout<<"Extern limit is "<<limit<<std::endl; return 0; }
由链接属性linkage的介绍,我们知道const变量是内部链接属性的,只能在转换单元内部访问。
而定义一个const变量,希望其他的转换单元都可以使用的情况是常见的,如圆周率PI,const double pi=3.14159265,
那么,怎么才能让const变量也具有外部链接属性呢。
我们只需要在定义const变量时,也加上extern关键字就可以了。
示例代码如下:
myextern.cpp extern const double pi=3.14159265; mymain.cpp int main() { extern const double pi; std::cout<<"Extern pi is "<<pi<<std::endl; return 0; }
另外需要说明的是,extern变量声明的位置,决定了该外部变量的作用域。
参考资料:《C++入门经典 第三版》 pp.309-318