3

我知道在类 C 语言中,我可以不使用运算符执行布尔not运算:(C)

int myBool = TRUE;
myBool = !myBool;

但我的问题是:这是如何在幕后实现的?我的猜测是使用跳转,但如果过度使用这些可能效率低下:(英特尔 x86 语法)

; assume eax holds boolean
  test eax, eax
  jnz short boolTrue
  inc eax ; eax was 0, now 1
  jmp short after
boolTrue: ; eax non-zero
  xor eax, eax ; eax now 0
after:

如图所示,它需要 5 条指令,其中至少有一个跳转和一个按位and( test)。if (!!fileHandle)必须有一种更简单的方法来做到这一点,因为我已经看到代码库出于某种奇怪的原因执行“双重非”( )。

所以(如上所述):编译器如何!在 x86 上执行 boolean ?

4

4 回答 4

4

您可以使用SETZ不需要分支的 (set (if) zero (flag is set)) 来执行此操作。

于 2012-12-12T16:28:13.197 回答
3

有可能使用进位和无分支序列:

sub %eax, 1        ;; this produces carry only when %eax EQ zero
sbb %eax, %eax     ;; 0 when not carry, -1 when carry
and %eax, 1        ;; just get the least significant bit (also neg %eax will do)

对于eax=!eax

sub %eax, 1        ;; 
sbb %eax, %eax     
add %eax, 1        ;; [-1, 0] + 1 == [0, 1]

eax = !!eax.

我不知道是否有 3 个指令(或更少)序列使用不会浪费原始变量(或寄存器 eax)的通用算术运算。

于 2012-12-13T07:01:24.803 回答
2

在一个好的编译器中,实现诸如 NOT 之类的运算符的方法通常不会仅限于一种代码生成模式。编译器将考虑周围上下文的许多因素,例如编译时优化、源代码和/或紧接在 NOT 运算符之前生成的代码,NOT 运算符是否用于条件上下文(例如,用于 if 语句)或值上下文(用于赋值)。

当在 if 语句中使用时,NOT 运算符更有可能使用分支来实现,因为 if 语句很可能无论如何都需要分支。在值上下文中使用时,NOT 运算符更有可能通过比较和捕获结果来实现(没有分支)。

在较大的表达式中使用 NOT 运算符时,通常可以反转嵌套运算符,因此以一种方式看待它,NOT 运算符根本不会生成任何代码;这可能发生在诸如a = ! (b > 0)or的表达式中if ( ! ( a && b ) )。即使使用if ( !a ),您也可能会发现 a 实际上并没有被 NOT 处理,而只是像 in 一样被测试if ( a ),尽管分支条件被颠倒了。

在您给出的具体示例中,我希望一个好的编译器尽最大努力(为生产而不是为调试生成代码),它将在编译时确定应该将常量0而不是myBool传递给printf.

简而言之,一个体面的编译器有许多可用的技术和许多标准来确定使用哪个。

于 2012-12-12T18:42:08.170 回答
0

如果您有适当的布尔值,则可以使用XOR在两种表示形式之间切换。请注意,C它没有布尔值,它只是将零解释为假,其他任何东西都解释为真。C++并且C#两者都有适当的布尔值,因此它们不需要弄乱非零检查,实际上至少g++确实使用了该XOR方法。

于 2012-12-12T16:58:09.590 回答