我会像编写将 C 转换为 mips 汇编的逻辑 OR 语句一样编写逻辑 AND 语句吗?
else if (i == x && j == y)
printf("%c", 219);
这是我放的
bne $reg1, $t3, draw219 # i==x
bne $reg2, $t4, draw219 # j==y
我们将根据需要使用 deMorgan 进行转换:
结构化 if-then-else 语句中的复合条件:
...
if ( i == x && j == y ) {
<then-part>
}
else {
<else-part>
}
...
在 if-goto-label 形式中,条件被否定,同时分支也指向 else 部分,因此将这两个更改放在一起,它仍然运行相同(它实际上是双重否定,因此相同的逻辑):
...
if ( ! (i == x && j == y) ) goto elsePart1;
thenPart1:
<then-part>
goto endIf1;
elsePart1:
<else-part>
endIf1:
...
可以通过对
&&
的操作数求反并更改为 ||
,将否定分布在合取上。
德摩根在否定条件上的应用:
if ( ! (i == x) || ! (j == y) ) goto elsePart1;
然后优化关系的否定:
if ( i != x || j != y ) goto elsePart1;
这可以分为两个 if 语句:
if ( i != x ) goto elsePart1;
if ( j != y ) goto elsePart1;
// will come here when the original if condition is true
这两条线很容易组装。
我们可以将
&&
转换为 &
作为另一种方法,因此我们可以评估两个操作数,然后简单地将结果 and
一起计算,并使用单分支指令进行测试,而不是实现短路运算符。德摩根也可以应用;而 ||
可以替换为 |
。
只有在代码允许的情况下,将短路运算符转换为非短路运算符才有效,这意味着程序需要始终执行/执行/评估第二个操作数。如果函数调用或数组引用受到第一个条件的保护,则不一定可以执行。这是一个何时不能转换短路运算符的示例:
if ( i < N && a[i] == 0 ) ...
数组引用受到使用短路运算符的范围检查的保护/保护,因此,如果将其转换为
&&
,有时会导致数组引用越界来评估 &
的两侧。
第二个操作数中的函数调用对于此转换也可能会出现问题。
以 || 开头时连接词如:
...
if ( c < 'a' || c > 'z' ) {
<then-part>
}
else {
<else-part>
}
...
首先转换为if-goto-label形式:
...
if ( ! ( c < 'a' || c > 'z' ) goto elsePart1;
thenPart1:
<then-part>
goto endIf1;
elsePart1:
<else-part>
endIf1:
...
DeMorgan,这个否定变成:
if ( ! ( c < 'a' ) && ! ( c > 'z' ) ) goto elsePart1;
通过颠倒关系:
if ( c >= 'a' && c <= 'z' ) goto elsePart1;
接下来,我们可以将复合 && if 语句拆分为两个 if 语句,通过调整目标并再次求反,这次只是其中的一半:
if ( c < 'a' ) goto thenPart1;
if ( c <= 'z' ) goto elsePart1;
thenPart1:
<then-part>
goto endIf1;
elsePart1:
<else-part>
endIf1;
如您所见,这次我们确实需要
thenPart1:
标签,而在其他转换中我们可能不会使用它。
另请注意,假设没有副作用,我们也可以将 && 转换为 &,就像 || 的转换一样到 |,这消除了复杂的条件。
你不小心搞反了你的逻辑。我假设“draw219”是一段相当于您的 C 代码的代码
printf("%c", 219);
。 bne
指令不应在那里分支,因为它们仅在两个寄存器不相等时才分支。当两个寄存器不相等时,总体 if
条件为 false,因此您应该分支到接下来要执行的任何代码块,但不要转到“draw219”。