首页 > 解决方案 > 将有符号整数除以 2 编译为复杂的汇编输出,而不仅仅是移位

问题描述

考虑这个 C 函数;

int triangle(int width, int height)
{
    return (width * height) / 2;
}

使用 gcc ( gcc -m32 -g -c test.c) 编译时会生成以下程序集 ( objdump -d -M intel -S test.o)。

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <triangle>:

int triangle(int width, int height)
{
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
    return (width * height) / 2;
   3:   8b 45 08                mov    eax,DWORD PTR [ebp+0x8]
   6:   0f af 45 0c             imul   eax,DWORD PTR [ebp+0xc]
   a:   89 c2                   mov    edx,eax
   c:   c1 ea 1f                shr    edx,0x1f
   f:   01 d0                   add    eax,edx
  11:   d1 f8                   sar    eax,1
  13:   5d                      pop    ebp
  14:   c3                      ret    

我已经知道将整数 n 位向右移动会将其除以 2^n。然而,根据上面的输出,有符号整数似乎被不同地对待(这当然是有道理的)。如果我正确读取程序集输出,则在移位之前将整数的符号位添加到自身。

在右移之前将整数的符号位添加到自身的目的是什么?

标签: assemblyx86

解决方案


这是为了得到负数的正确“四舍五入”结果。通过将轮数移向负无穷来进行除法,因此与 C 除法运算符的预期结果相比,负数将具有不同的结果。

一个例子是 -1:右移 1 仍然给出 -1,但 C 运算符/ 2给出 0。

所以额外的代码是对这种效果的修正。如果您不需要,请使用无符号或显式移位(但第二个选项的可移植性较差)。


推荐阅读