知识点回顾
1. 作用域
上一讲我们是从变量的作用域角度将变量划分为局部变量和全局变量,这是从空间的角度来分析的。我们发现当变量被定义在程序的不同位置时,它的作用范围是不一样的。这个作用范围就是我们所说的作用域。
那么 C 语言编译器可以确认 4 种不同类型的作用域:代码块作用域、文件作用域、原型作用域和函数作用域。
1.1 代码块作用域(block scope)
最常见的就是代码块作用域。所谓代码块,就是位于一对花括号之间的所有语句。
1.2 文件作用域(file scope)
任何在代码块之外声明的标识符都具有文件作用域,作用范围是从它们的声明位置开始,到文件的结尾处都是可以访问的。另外,函数名也具有文件作用域,因为函数名本身也是在代码块之外。
1.3 原型作用域(prototype scope)
原型作用域只适用于那些在函数原型中声明的参数名。我们知道函数在声明的时候可以不写参数的名字(但参数类型是必须要写上的),其实多尝试你还可以发现,函数原型的参数名还可以随便写一个名字,不必与形式参数相匹配(当然,这样做毫无意义)。允许你这么做,只是因为原型作用域起了作用。
1.4 函数作用域(function scope)
函数作用域只适用于 goto 语句的标签,作用将 goto 语句的标签限制在同一个函数内部,以及防止出现重名标签。
2. 定义和声明
当一个变量被定义的时候,编译器为变量申请内存空间并填充一些值。当一个变量被声明的时候,编译器就知道该变量被定义在其他地方。声明通知编译器该变量名及相关的类型已存在,不需要再为此申请内存空间。
3. 链接属性
简单的来说,编译器将你的源文件变成可执行程序需要经过两个步骤:编译和链接。编译过程主要是将你写的源代码生成机器码格式的目标文件,而链接过程则是将相关的库文件添加进来(比如你在源文件中调用了 stdio 库的 printf 函数,那么在这个过程中,就把 printf 函数的代码添加进来),然后整合成一个可执行程序。
当然,这是最简单的介绍,大家有兴趣可以看一下这篇扩展阅读:编译器的工作流程,这里说这个,主要是我们要引入一个新的知识,叫做链接属性。
链接属性是个什么东西呢?
我们知道大型的程序都有好些个源文件构成,那么在不同文件中的同名标识符,编译器是如何处理的呢?这就要看链接属性了。
在 C 语言中,链接属性一共有三种:
· external(外部的)-- 多个文件中声明的同名标识符表示同一个实体
· internal(内部的)-- 单个文件中声明的同名标识符表示同一个实体
· none(无)-- 声明的同名标识符被当作独立不同的实体(比如函数的局部变量,因为它们被当作独立不同的实体,所以不同函数间同名的局部变量并不会发生冲突)
默认情况下,具备文件作用域的标识符拥有 external 属性。也就是说该标识符允许跨文件访问。对于 external 属性的标识符,无论在不同文件中声明多少次,表示的都是同一个实体。
使用 static 关键字可以使得原先拥有 external 属性的标识符变为 internal 属性。这里有两点需要注意:
1. 使用 static 关键字修改链接属性,只对具有文件作用域的标识符生效(对于拥有其他作用域的标识符是另一种功能)
2. 链接属性只能修改一次,也就是说一旦将标识符的链接属性变为 internal,就无法变回 external 了




