15.5 作用域
作用域 (Scope) 描述“一个标识符在源代码中可见的区域”。它是静态语义规则,与对象是否已经创建是两个概念。理解作用域可以直接避免命名冲突、阴影覆盖和接口泄露。
1. 四种常见作用域
四种作用域及其区间
文件作用域从声明点持续到翻译单元结尾;块作用域从声明点持续到当前复合语句结束;函数原型作用域只在函数声明的形参列表内有效;标号作用域覆盖整个函数体。它们共同决定同名标识符何时表示同一个实体,何时表示不同实体。
2. 块作用域与阴影覆盖
c
#include <stdio.h>
int main(void) {
int x = 1;
{
int x = 2;
printf("inner x = %d\n", x);
}
printf("outer x = %d\n", x);
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
输出:
bash
inner x = 2 outer x = 1
3. 函数原型作用域
函数声明中的形参名只在该原型内部有效,它们主要用于可读性和文档化,不会在原型外形成可见名字。
c
int add(int left, int right); /* left/right 仅在这个声明里有效 */
int add(int a, int b) {
return a + b;
}1
2
3
4
5
2
3
4
5
定义阶段可以使用不同的形参名,类型匹配才是关键约束。
4. 标号作用域补充
label: 的可见范围覆盖整个函数体,因此 goto 可以跨块跳转到该标号,但目标仍必须位于同一函数内。它不受普通块作用域限制。
c
int f(int x) {
if (x < 0) {
goto fail;
}
return 0;
fail:
return -1;
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
这类写法常用于统一失败出口,但仍应控制在清晰、可验证的范围内。
5. 声明点的时间边界
块作用域从声明点开始
块作用域标识符并不是“进入块就可见”,而是从声明点之后才可见。
c
int x = 1;
{
/* 此处仍是外层 x 可见 */
int x = 2; /* 从这里开始,内层 x 可见 */
}1
2
3
4
5
2
3
4
5