链接和作用域
让编程改变世界
Change the world by program
链接和作用域
前边我们已经开始创建由多个文件构成的项目,是时候再来讨论下更复杂的变量作用域了。 简单的理解,变量的作用域就是你可以在什么范围内访问这个变量。 地球人都知道,一个在任何函数之前定义的变量可以在任何一个函数里使用(这是一个全局变量),而在某个函数里定义的变量只能在那一个函数里使用(这是一个局部变量)。 那么,当一个项目由多个文件构成时,变量的作用域也会受到一定的影响! 与作用域有关的另一个概念是链接,当你同时编译多个文件时:g++ -o test main.cpp rational.cpp
每个源文件都被称为一个翻译单元(translation unit),在某一个翻译单元里定义的东西在另一个翻译单元里使用正是链接发挥作用的地方。 作用域、链接和存储类是相互关联的概念,它们有许多共同的术语,只是观察和描述问题的角度不同罢了。存储类(storage class)
每个变量都有一个存储类,它决定着程序将把变量的值存储在计算机上的神马地方、如何存储,以及变量应该有着怎样的作用域。 默认的存储类是auto(自动),但你不会经常看到这个关键字,因为它是默认的,阴魂不散的! 自动变量存储在称为栈(stack)的临时内存里并有着最小的作用域,当程序执行到语句块或函数末尾的右花括号时,它们将被系统回收(栈回收),不复存在。 与auto不同的是static,static变量在程序的生命期内将一直保有它的值而不会消亡,因为它们是存储在静态存储区,生命周期为从申请到程序退出(和全局变量一样)。 另外我们稍后就会提到的,一个static变量可以有external或internal链接。 第三种存储类是extern,它在有多个翻译单元时非常重要。这个关键字用来把另一个翻译单元里的某个变量声明为本翻译单元里的一个同名全局变量。 注意,编译器不会为extern变量分配内存,因为在其他地方已经为它分配过内存。 用extern关键字相当于告诉编译器:“请相信我,我发誓我知道这个变量在其他翻译单元里肯定存在,它只是没在这个文件里声明而已!” 还有一个存储类是register,它要求编译器把一个变量存储在CPU的寄存器里。但有着与自动变量相同的作用域。 register变量存储速度最快,但有些编译器可能不允许使用这类变量。变量的链接和作用域
链接是一个比较深奥的概念,所以我们尽可能以浅显的文字来解释它。在使用编译器建议程序时,它实际上是由3个步骤构成:
- 执行预处理器指令;
- 把.cpp文件编译成.o文件;
- 把.o文件链接成一个可执行文件。
// this.cpp int i1 = 1; // that.cpp int i2 = i1;[/codesyntax] 不用试了,一看就有问题,对不对?!在编译that.cpp文件时,编译器并不知道i1变量的存在。 为了解决这个问题,我们可以在that.cpp里使用extern关键字去访问第一个翻译单元的变量。 [codesyntax lang="c"]
// this.cpp int i1 = 1; // that.cpp extern int i1; int i2 = i1;[/codesyntax] 内链接的含义是:在某个翻译单元里定义的东西只能在翻译单元里使用,在任何函数以外定义的静态变量都有内链接: [codesyntax lang="c"]
// this.cpp static int d = 8; // that.cpp static int d = 9;[/codesyntax] 这两个文件各有一个同名的变量,但它们是毫不相干的两样东西。 最后,在函数里定义的变量只存在于该函数的内部,根本没有任何链接(none)。 小甲鱼相信,现在众鱼油的心里肯定有十万只草泥马在奔腾! 但是,如果你能把上面这些关于作用域和链接的事情都搞清楚,就会发现这几个话题其实是彼此紧密相关的,把课件好好再看一遍。 下节课给大家带来巩固这些个概念的练习,敬请期待和准时收看。 [buy] 获得所有教学视频、课件、源代码等资源打包 [/buy] [Downlink href='http://urlxf.qq.com/?qQfINnA']视频下载[/Downlink] [Downlink href='http://kuai.xunlei.com/d/LFGSRSYLNSYD']备胎下载[/Downlink]