INT_MIN*-1是x86上的无操作吗?

Vil*_*ray 2 x86 signed integer-overflow undefined-behavior

有符号整数在x86上通过二进制补码表示,其中符号位具有该值-(2^N).这导致在-2^N2^N - 1(例如-32768通过32767)之间的典型可表示值范围.

我很好奇如果我在我的系统上取最小有符号整数值并乘以它以-1试图"强制"一个大于我系统上有符号整数的最大可表示值的最大值,会发生什么.

#include <stdio.h>
#include <limits.h>

int main(void){
    signed int x, y;

    x = INT_MIN;
    y = x * -1;

    printf("%d\n%d\n", x, y);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这导致以下输出:

# gcc -std=c89 -pedantic int_min_test.c

# ./a.out
-2147483648
-2147483648
Run Code Online (Sandbox Code Playgroud)

我期待一个整数溢出(导致典型的值翻转),但看起来似乎没有关于xwith 的乘法操作-1.

在x86中是否INT_MIN-1no-op 相乘?

R..*_*R.. 5

对于 C(基于问题的原始标记,以及用 C 编写的示例代码),这是未定义的行为,所以不,C 表达式的结果INT_MIN * -1不是“无操作”,而是未定义的行为。实际上,根据观察方式的不同,观察到的结果可能会不一致,甚至可能在时间上不一致。不要这样做。

如果您想询问 x86imul指令,那是另一个问题,我相信(32 位)imulby0x800000000xffffffff产生0x80000000。但这与您期望在 C 中看到的内容无关。

  • 当问题中的代码是 C 时,仅更改标记并没有真正的帮助。如果您想询问有关 asm 的信息,请使用 asm 示例代码。C 不直接翻译为 asm。 (2认同)
  • 是的,“imul”生成完整的双宽度结果并截断。因此,您可以检查类似“calc”的内容:“0x80000000 * 0xffffffff”=&gt;“0x7fffffff80000000”(无符号计算,这很好,因为我们只保留低半部分)。所以是的,低半部分是“0x80000000”,这就是您从 imul 的双操作数或立即数形式得到的结果。 (2认同)

Ald*_*den 5

使用gcc 4.8.5,y = x * -1;使用以下指令计算行:

neg    %eax
Run Code Online (Sandbox Code Playgroud)

neg操作翻转该字的位然后加1.对于32位2的补码,结果为:

0x80000000 # Start value
0x7FFFFFFF # Flip bits
0x80000000 # Add 1
Run Code Online (Sandbox Code Playgroud)

如您所见,计算机正在完全按照您的要求执行操作.这不是一个空操作,如neg修改AF,CF,OF,PF,SF,和ZF标志.它只是所使用的二进制表示的工件.正如其他人所说,它只是未定义的行为.