Visual C++生成DIV而不是IDIV(x86,整数运算)

nie*_*lsj 3 c++ assembly integer-division visual-c++-2008

我在这里使用Visual C++ 2008(9.x),当我遇到生成DIV而不是IDIV的编译器时,我正准备一个固定点值.我将代码折叠成一小块以完全重现:

short a = -255;
short divisor16 = 640; // unsigned, 16-bit
unsigned int divisor32 = 640; // unsigned, 32-bit
unsigned short s_divisor16 = 640; // signed, 16-bit
int s_divisor32 = 640; // signed, 32-bit
int16_t test1 = (a<<8)/divisor16; // == -102, generates IDIV -> OK
int16_t test2 = (a<<8)/s_divisor16; // == -102, generates IDIV -> OK
int16_t test3 = (a<<8)/divisor32; // == bogus, generates DIV -> FAIL!
int16_t test4 = (a<<8)/s_divisor32; // == -102, generates IDIV -> OK

int bitte_ein_breakpoint=1;
Run Code Online (Sandbox Code Playgroud)

我不会用简单的反汇编来打扰你.

现在不是采用快捷方式而只是改变除数的类型(它是一个函数参数,unsigned int numPixels),我想知道是什么让编译器在第三个(test3)情况下选择DIV而不是IDIV,因为它没有这样做无符号的16位除数,实际上没有任何东西可以调用无符号算术.至少那是我的想法,我希望我错了:)

Rol*_*lig 7

/运算符生成的代码取决于操作数.

首先,表达式(a << 8)具有类型int,因为对每个操作数(ISO C99,6.5.7p3)执行整数提升,然后操作int << int,这导致一个int.

现在有四种表达方式:

  1. int / short:右手边提升int,因此idiv指示.
  2. int / unsigned short:右手边提升int,因此idiv指示.
  3. int / unsigned int:左侧被提升为unsigned int,因此div指令.
  4. int / int:没有任何提升,因此idiv指示是适当的.

整数促销活动在ISO C99 6.3.1.1p3定义:

如果a int可以表示原始类型的所有值,则该值将转换为int; 否则,它被转换为unsigned int.这些被称为整数促销..