布尔人如何在集会中“注意到”?

时间:2012-12-12 16:24:53

标签: assembly compilation x86 boolean-logic

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

int myBool = TRUE;
myBool = !myBool;

但我的问题是:这是如何在幕后实现的?我的猜测是使用跳转,但如果过度使用则效率低下:( Intel 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条指令,至少有一个跳转,一个按位andtest)。必须有一个更简单的方法来实现这一点,因为我已经看到代码库基于某些奇怪的原因而做了“双重注意”(if (!!fileHandle))。

所以(如上所述):编译器如何在x86上进行布尔!

4 个答案:

答案 0 :(得分:4)

您可以使用SETZ(设置(如果)为零(设置标志))来执行此操作,但不需要分支。

答案 1 :(得分:2)

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

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)的常见算术运算。

答案 2 :(得分:1)

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

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

当在较大的表达式中使用NOT运算符时,通常可以反转嵌套运算符,因此对于一种查看它的方法,NOT运算符根本不生成代码;这可能发生在a = ! (b > 0)if ( ! ( a && b ) )等表达式中。即使使用if ( !a ),您也可能会发现a实际上并未被忽略,而只是在if ( a )中进行测试,但分支条件已反转。

在您给出的具体示例中,我希望编译器能够做出最好的努力(为生产而不是为调试生成代码),它会在编译时确定常量0而不是{{1应该传递给myBool

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

答案 3 :(得分:0)

如果你有一个合适的布尔值,你可以使用XOR在两个表示之间切换。请注意C没有bool,它只将零解释为false,其他任何东西都为true。 C++C#都有适当的布尔值,因此他们不需要使用非零检查,实际上至少g++确实使用了XOR方法。

相关问题