链接性
标识符在不同翻译单元中是否指向同一个实体,发生在 链接期
作用域
标识符在源代码中的可见范围,发生在 编译期
块作用域
被 '{}' 包裹所形成的代码块,定义的变量只能在这个块内使用
比如if语句,while语句等等,这里需要注意的是 switch-case 语句,它整个就是一个块作用域,如果重复定义一个变量会报错,示例如下
char c;
...
switch (c) { // 整个switch-case是一个块作用域
case 'a':
int count = 1; // 第一次定义count
break;
case 'b':
int count = 2; // 第二次定义count
break;
}
在这个示例中,每个case都是属于同一个作用域,所以count相当于在这个作用域内定义了多次,解决方法有两种,一个是在switch-case语句的外部定义,还有一种就是给case加上一个块作用域,独立于switch-case的这个大的作用域
// 法1
int count; // 在外部定义
switch (c) {
case 'a': ...
case 'b': ...
}
// 法2
switch (c) {
case 'a': {...} // 形成单独的作用域
case 'b': {...}
}
函数作用域
函数作用域是一个特殊的块作用域,它是函数实现的顶层块作用域,比如函数的参数就具有函数作用域
还有一个是,在函数内定义的标签(如 goto 标签)具有函数作用域,这意味着标签只在定义它的函数内有效,示例如下
#include <stdio.h>
void func() {
goto label; // label 只能在 func 函数内使用
label:
printf("This is a label.\n");
}
int main() {
func();
printf("%s", label); // 错误:label 在这里不可见
return 0;
}
文件作用域
在文件顶部定义的变量和函数在整个文件中可见,比如全局变量,可以在一个或多个源文件中使用
总结
什么时候提作用域/链接性
-
分阶段:
-
编译期 -> 作用域
-
链接期 -> 链接性
-
-
分目的:
-
分析标识符的 可见性(适用范围) -> 作用域
-
分析标识符的 实体同一性(标识符要有唯一对应的实体),比如一份函数原型,它对应的实体(即实现)只能唯一
-
static的作用
- 限制作用域,将标识符限制在一个文件中使用,避免同名冲突,链接冲突(这些冲突是发生在多个文件中的,限制在一个文件内,这些冲突就没了)
特别提一点,我们这里只提及他对 作用域和链接性 的影响,而不是对 生命周期 的影响
作用域就块/函数/文件这三个吗
可能有其他的,但这三个最主要,他们的特殊情况可能成为新的 作用域名词
作用域/链接性/生命周期
这三个概念容易混淆,作用域强调的是 标识符的使用范围,链接性强调的是 标识符和实体的对应,生命周期强调的是 标识符的创建和销毁
举个例子
int add(int x)
{
static int sum = 0;
sum += x;
return sum;
}
这里的sum变量,他的作用域是 块作用域,因为是顶层块作用域,所以也可以成为函数作用域,没有链接性(只在定义的文件中使用),生命周期则是 贯穿程序始终
posted on
浙公网安备 33010602011771号