程序中的 fall-through 行为分析
最近移指 dyninst 的时候,发现指令解析模块涉及到 fall-through 概念,查了些英文资料后,初步了解了这个概念。
wiki 上的解释
- fall-through(fallthrough and fall through)
(programming) In certain programming constructs, the situation where execution passes to the next condition in a list unless explicitly redirected. (【编程】)在某些编程构造中,除非明确重定向,否则执行转移到列表中的下一个条件的情况。
1997, Bjarne Stroustrup, The C++ Programming Language: Language Libraries and Design:
It is a good idea to comment the (rare) cases in which a fall-through is intentional so that an uncommented fall-through can be assumed to be an error. 最好对故意失败的(罕见)情况进行注释,以便将未注释的失败视为错误。2001, Graham M Seed, Barry J Cooper, An Introduction to Object-Oriented Programming in C++
If you place default elsewhere, then a break will be required to prevent fall-through. 如果您在其他地方设置了默认值,则需要中断以防止失败。2008, Nagel et al, Professional C# 2008
Specifically, it prohibits fall-through conditions in almost all cases. 具体来说,它禁止在几乎所有情况下出现故障。
branch 指令中的体现
branch 指令包含两类:conditional 和 unconditional,分支指令中的指令流执行路径可分为两种:
target path:指的是将要跳转的位置,例如 C 中 goto 跳转的标签。
fall-through path:指的是紧跟分支指令之后的指令。
如下图所示,从 C 语言角度来看,当条件满足 a 等于 b 的时候,就会跳转到 target address,不满足则进入到 fall through address;从汇编角度来看,当判断条件寄存器 cr0 表示相等时,就跳转到 target address,不相等时则执行紧跟分支指令的下一条指令,即正常的 pc+4;
switch 语句中的体现
fall-through 行为的示例
示例:
1 | int result = 5; |
毫无疑问,上述代码块执行结果是:The result is 5
,但如果删掉每条 case 里的 break 语句后,结果就不可控了,代码如下:
1 | int result = 5; |
Case 5, case 10 和 default case 都会被执行,这就是 switch 语句中的 fall-through 行为表现。
fall-through 行为的好处
这里的 fall-through 行为看上去好像 bug,但事实上并不是,该行为也是有用处的,常用来分类一些相关联的 cases,例如下面代码:
1 | int result = 10; |
当 result 为 10 时,进入 case 10,打印:The result is 10。
当 result 为 1 时,进入 case 1,打印:The result is less than 10。
当 result 为 2 时,进入 case 2,打印:The result is less than 10。
当 result 为 5 时,进入 case 5,打印:The result is less than 10。
可以看出,后面三种情况是有关联的,并且打印内容是一样的,因此可以删掉 break,通过 fall-through 行为来归类相关联的 cases,这便是该行为的好处。修改后代码如下:
1 | int result = 10; |