5.2 if…else…语句(1)
5.1节讲述了if语句的构成,但是,只有if的语句是不完整的分支结构,图5-1对比了两种语句结构的执行流程。
|
| 图5-1 if与if…else…结构对比 |
如图5-1所示,if语句是一个单分支结构,if…else…组合后是一个双分支结构。两者间完成的功能有所不同。从语法上看,if…else…只比if语句多出了一个else。else有两个功能,如果if判断成功,则跳过else分支语句块;如果if判断失败,则进入else分支语句块中。有了else语句的存在,程序在进行流程选择时,必会经过两个分支中的一个。通过代码清单5-3,我们来分析else如何实现这两个功能。
代码清单5-3 if…else…组合—Debug版
- // C++(www.cppentry.com)源码说明:if…else…组合
- if (argc == 0) {
- // 执行if语句块
- printf("argc == 0");
- }else{
- // 执行else语句块
- printf("argc != 0");
- }
-
- // C++(www.cppentry.com)源码与对应汇编代码讲解
- // C++(www.cppentry.com)源码对比,比较参数变量argc == 0
- if (argc == 0)
- ; 使用变量argc减去0
- 004010B8 cmp dword ptr [ebp+8],0
- ; 使用条件跳转JNE,检查cmp影响标记位
- ; 跳转成立,跳转到地址0x004010CD处,即else语句块的首地址
- 004010BC jne IfElse+2Dh (004010cd)
- {
- // C++(www.cppentry.com)源码对比,进入if语句块,调用printf函数
- printf("argc == 0");
- ; printf函数汇编讲解略
- }else
- ; 直接跳转到地址0x004010DA地址处,当if语句执行后跳转过else语句块
- 004010CB jmp IfElse+3Ah (004010da)
- {
- // C++(www.cppentry.com)源码对比,进入else语句块,调用printf函数
- printf("argc != 0");
- ; printf函数汇编讲解略
- 004010CD push offset string "argc != 0" (00420030)
- 004010D2 call printf (00401150)
- 004010D7 add esp,4
- }
- ; else语句结束处
- 004010DA pop edi
在代码清单5-3中,if语句转换的条件跳转和代码清单5-1中的if语句相同,都是取相反的条件跳转指令。而在else处(地址004010CB)多了一句jmp指令,这是为了在if语句比较后,如果结果为真,则程序流程执行if语句块并且跳过else语句块,反之执行else语句块。else处的jmp指令跳转的目标地址为else语句块结尾处的地址,这样的设计可以跳过else语句块,实现两个分支语句二选一的功能。
4.2.3节介绍了条件表达式,当条件表达式中的表达式2或表达式3为变量时,没有进行优化处理。条件表达式转换后的汇编代码和if…else…结构非常相似,将代码清单4-17与代码清单5-3进行分析对比可以发现,两者间有很多相似之处,如没有源码比照,想要分辨出是条件表达式还是if…else…结构实在太难。它们都是先比较,然后再执行条件跳转指令,最后进行流程选择的。
通常,VC++(www.cppentry.com) 6.0对条件表达式和if…else…使用同一套处理方式。代码清单5-3对应条件表达式转换方式4。将代码清单5-3稍作改动,改为符合条件表达式转换方式1的形式,如代码清单5-4所示。
代码清单5-4 模拟条件表达式转换方式1
- // C++(www.cppentry.com)源码说明:if…else…模拟条件表达式转换方式1
- if (argc == 0){ // 等价条件表达式中的表达式1
- // 修改上例,将上例中的printf函数替换成变量赋值语句
- argc = 5; // 等价条件表达式中的表达式2
- }else{
- // 代码上例,将上例中的printf函数替换成变量赋值语句
- argc = 6; // 等价条件表达式中的表达式3
- }
- // 防止变量被优化处理
- printf("%d \r\n", argc);
-
- // Debug调试版,由于注重调试功能,没有进行优化,反汇编讲解如下
- 22: if (argc == 0){
- ; 直接与0进行比较,注意后面的jne,如果不相等就跳走,C源码中的逻辑与汇编代码相反
- 00401098 cmp dword ptr [ebp+8],0
- 0040109C jne main+27h (004010a7)
- 23: argc = 5;
- ; 这里是if语句块的内容,将参数赋值为5
- 0040109E mov dword ptr [ebp+8],5
- 24: }else{
- ; 注意这里的跳转,正好跳出了else块
- 004010A5 jmp main+2Eh (004010ae)
- 25: argc = 6;
- ; 这里是else语句块的内容,将参数赋值为6
- 004010A7 mov dword ptr [ebp+8],6
- 26: }
- 27: printf("%d \r\n", argc);
- ; printf函数汇编讲解略
- 004010AE ......