这就是 C 库函数 abs() 在汇编中不分支的方式:
abs(x) = (x XOR y) - y
其中y = x >>> 31(假设输入为 32 位),>>> 是算术右移运算符。
上式解释:
我们只想生成负 x 的 2 补码。
y = 0xFFFF, if x is negative
0x0000, if x is positive
所以当 x 为正时 x XOR 0x0000 等于 x 。当x 为负时,x XOR 0xFFFF 等于x 的补码。现在我们只需要添加 1 来得到它的 2 的补码,这就是表达式 -y 正在做的事情。因为0xFFFF 在十进制中是 -1。
让我们看看gcc(我的机器上是4.6.3)为以下代码生成的程序集:
C 代码:
main()
{
int x;
int output = abs(x);
}
gcc 4.6.3 使用我的 cmets 生成程序集 sn-p(AT&T 语法):
movl -8(%rbp), %eax # -8(%rbp) is memory for x on stack
sarl $31, %eax # shift arithmetic right: x >>> 31, eax now represents y
movl %eax, %edx #
xorl -8(%rbp), %edx # %edx = x XOR y
movl %edx, -4(%rbp) # -4(%rbp) is memory for output on stack
subl %eax, -4(%rbp) # (x XOR y) - y
BONUS(来自Hacker's Delight):如果您有一个快速乘以 +1 和 -1,以下将为您提供 abs(x):
((x >>> 30) | 1) * x