3

我在这里使用 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;

我不会用简单的拆卸来打扰你。

现在不是走捷径,只是改变除数的类型(它是一个函数参数,unsigned int numPixels),我想知道是什么让编译器在第三个(test3)案例中选择 DIV 而不是 IDIV,因为它没有这样做无符号的 16 位除数,实际上没有任何东西需要无符号算术。至少我是这么想的,我希望我错了:)

4

2 回答 2

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 中定义:

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

于 2011-08-20T12:41:55.773 回答
1

左移一个负值会导致未定义的行为。所以我不确定你能从编译器在这种情况下选择做什么得出很多结论。

于 2011-08-20T12:41:08.037 回答