if 语句的作用域
archive time: 2021-06-04
今天我们来看看 C 语言中作用域的例子
缘起
最近看到群里有个人问了个比较有意思的问题
main() {
int a = 3, b = 4, c = 5, t = 99;
if (b < a && a < c) t = a; a = c; c = t;
if (a < c && b < c) t = b; b = a; a = t;
printf("%d%d%d\n", a, b, c);
}
问这个程序的输出是什么
只要顺着程序逻辑看简单推算即可得知输出结果应该是 4599
但是那人却继续问: “那两个 if
中不是做了交换操作吗?
第一个 if
不执行,而第二个执行,所以 b
被赋上了a
的值,a
赋上了b
的值,c
不变,
所以答案不应该是 435
吗?”
这个错误可谓是十分经典了,很多初学者面对这些格式不规范的 谭氏 C 语言1 总是不知所措
在这里,他将if
的作用域当成了该语句所在的那一行了,而忽略了 ;
的作用
C 语言的作用域
作用域2,简单说,就是说这个语句或者变量,它的影响范围有多广,
最直观的一类作用域的就是 block scope
,也就是被一对花括号 (curly bracket) 包裹起来的区域
for (int i = 0; i < n; ++i) {
// do some
...
}
在这样一个 for
循环里,i
就具有 块作用域,
也就是说 i
仅在它在被声明开始到花括号结束为止,这个范围内有效,
其他范围都不会被 i
影响
作用域分类
在 C 语言里,最规范的分类,应该有以下 四个 作用域的分类:
- block scope
- function scope
- function prototype scope
- file scope
其中最为常见的就是 block scope
,
因为在 C 语言里,用来组织语句的方式就是代码块,
或者说,用一对大括号将一堆语句括起来
其次就是 function prototype scope
,
这个作用域的定义就是在函数原型,
或者说声明语句内,其中声明的变量具有函数原型作用域
void exampleFunction(int paramA, double paramB[paramA]);
就比如上面这个例子,paramA
和 paramB
都具有函数原型作用域,
也是就是说他们的影响范围仅在这样一条语句内,对之后的所有语句或代码块都不会有所影响,
出了这条语句,也无法再次访问这个参数变量了
该作用域同时说明了,函数原型中重要的不是变量名,而是其类型,
在有函数重载的语言里,比如 Java
,
如何判断一个函数和另一个同名函数是重复还是重载,看的是其参数列表的参数的 类型,
参数列表的类型都一一对应的话,如果无继承关系,那么就是 函数重复,而非 函数重载,
若参数列表的参数的类型有所不同,那么就是 函数重载
function scope
是针对于跳转语句 (jump statement) 而言的,
说的是在一个函数内声明的 label
的作用域范围是整个函数,但超出这个函数的限定范围就不在生效
这也是为什么在同一个函数内不能有两个相同名称的标签的原因,因为会产生歧义,无法正常解析究竟要跳转到哪个标签
file scope
就是所谓的 全局作用域,
这个全局指的就是一个编译单元3,通常就是一个.c
文件,
因为一个.c
文件和一个.o(bj)
文件一般而言是对应的,而在 C 语言里,一个.o(bj)
就是所谓的编译单元
来看看这道题
这道题的代码,我们格式化 (format) 一下,就看得很清楚了
int main(void) {
int a = 3, b = 4, c = 5, t = 99;
if (b < a && a < c)
t = a;
a = c;
c = t;
if (a < c && b < c)
t = b;
b = a;
a = t;
printf("%d%d%d\n", a, b, c);
return 0;
}
实际上,这里的 if
就是单个语句,
比如 if (b < a && a < c) t = a;
这条语句,这就是它的作用域,
并且通过缩进我们也可以清楚地知道,if
所管理的语句就只有 t = a;
,是无法处理之后的语句的
所以我们带入相关逻辑就可知道,a = c
,c = t
,t = b
, b = a
,最后 a = t
,
再代入相应的值 a = 3, b = 4, c = 5, t = 99
,就可以知道
a* = b = 4
b* = c = 5
c* = t = 99
所以答案自然是 4599
这是一道很简单的逻辑推理题,但是主要考察的地方在于对于作用域的判断上, 还是一个比较容易犯错的点,这同时也说明了有一个好的编程风格和习惯是一件多么重要的事
谭浩强所著的 C 语言教材多以这类不规范的代码书写,经常有初学者出现一个程序 999error的事迹, 因此得名
参考网站,cppreference
又称翻译单元