IF 结构包含一个布尔表达式,其后有两个语句列表:一个是当表达式为真时执行,另一个是当表达式为假时执行:
结构中的 else 部分是可选的。在汇编语言中,则是用多个步骤来实现这种结构的。首先,对布尔表达式求值,这样一来某个 CPU 状态标志位会受到影响。然后,根据相关 CPU 状态标志位的值,构建一系列跳转把控制传递给两个语句列表。
【示例 1】下面的 C++ 代码中,如果 op1 等于 op2,则执行两条赋值语句:
if( op1 = op2 )
{
X = 1;
Y = 2;
}
在汇编语言中,这种 IF 语句转换为条件跳转和 CMP 指令。由于 op1 和 op2 都是内存操作数(变量),因此,在执行 CMP 之前,要将其中的一个操作数送入寄存器。
下面实现 IF 语句的程序是高效的,当逻辑表达式为真时,它允许代码“通过”直达两条期望被执行的 MOV 指令:
mov eax, op1
cmp eax,op2 ; op1 == op2?
jne L1 ; 否:跳过后续指令
mov X, 1 ; 是:X, Y 赋值
mov Y, 2
L1:
如果用 JE 来实现 == 运算符,生成的代码就没有那么紧凑了(6 条指令,而非 5 条指令):
mov eax, op1
cmp eax,op2 ; op1 == op2?
je L1 ; 是:跳转到 L1
jmp L2 ; 否:跳过赋值语句
LI: mov X, 1 ; X, Y 赋值
mov Y, 2
L2 :
从上面的例子可以看出,相同的条件结构在汇编语言中有多种实现方法。上面给出 的编译代码示例只代表一种假想的编译器可能产生的结果。
【示例 2】NTFS 文件存储系统中,磁盘簇的大小取决于磁盘卷的总容量。如下面的伪代码所示,如果卷大小(用变量 terrabytes 存放)不超过 16TB,则簇大小设置为 4096。否则, 簇大小设置为 8192:
用汇编语言实现该伪代码:
mov clusterSize, 8192 ;假设较大的磁盘簇
cmp terrabytes, 16 ;小于 16TB?
jae next
mov clusterSize, 4096 ;切换到较小的磁盘簇
next:
【示例 3】下面的伪代码有两个分支:
用汇编语言翻译这段伪代码,设 op1 和 op2 是有符号双字变量。对这两个变量比较时,其中一个必须送入寄存器:
mov eax, op1 ; opl送入寄存器
cmp eax, op2 ; opl > op2?
jg A1 ; 是:调用 Routine1
call Routine2 ; 否:调用 Routine2
jmp A2 ;退出工F语句
A1: call Routine1
A2:
复杂条件语句可能有多个执行路径,这使得它们难以进行调试检查(查看代码)。程序员经常使用的技术称为白盒测试,用来验证子程序的输入和相应的输出。
白盒测试需要源代码,并对输入变量进行不同的赋值。对每个输入组合,要手动跟踪源代码,验证其执行路径和子程序产生的输出。下面,通过嵌套 IF 语句的汇编程序来看看这个测试过程:
if op1 == op2
if X > Y
call Routine1
else
call Routine2
end if
else
call Routine3
end if
下面是可能的汇编语言翻译,加上了参考行号。程序改变了初始条件(op1 == op2),并立即跳转到 ELSE 部分。剩下要翻译的内容是内层 IF-ELSE 语句:
mov eax, op1
cmp eax, op2 ;op1 == op2?
jne L2 ;否:调用 Routine3
; 处理内层 IF-ELSE 语句。
mov eax, X
cmp eax, Y ; X > Y?
jg L1 ; 是:调用 Routine1
call Routine2 ; 否:调用 Routine2
jmp L3 ; 退出
L1: call Routine1 ; 调用 Routine1
jmp L3 ; 退出
L2: call Routine3
L3:
下表给出了示例代码的白盒测试结果。前四列对 op1、op2、X 和 Y 进行测试赋值。第 5 列和第 6 列对生成的执行路径进行了验证。
op1 | op2 | X | Y | 执行行序列 | 调用 |
---|---|---|---|---|---|
10 | 20 | 30 | 40 | 1, 2, 3, 11, 12 | Rountine3 |
10 | 20 | 40 | 30 | 1, 2, 3, 11, 12 | Rountine3 |
10 | 10 | 30 | 40 | 1, 2, 3, 4, 5, 6, 7, 8, 12 | Rountine2 |
10 | 10 | 40 | 30 | 1, 2, 3, 4, 5, 6, 9, 10, 12 | Rountine1 |