INT_MIN*-1在x86上是不可用的吗?

INT_MIN*-1在x86上是不可用的吗?,x86,undefined-behavior,signed,integer-overflow,X86,Undefined Behavior,Signed,Integer Overflow,有符号整数在x86上通过2的补码表示,其中符号位的值为-(2^N)。这导致典型的可表示值范围介于-2^N和2^N-1之间(例如-32768到32767) 我很好奇,如果我在系统上取最小有符号整数值,并将其乘以-1,试图“强制”一个大于系统上有符号整数的最大可表示值的最大值,会发生什么 #包括 #包括 内部主(空){ 符号int x,y; x=整数分钟; y=x*-1; printf(“%d\n%d\n”,x,y); 返回0; } 这导致了以下输出: # gcc -std=c89 -pedant

有符号整数在x86上通过2的补码表示,其中符号位的值为
-(2^N)
。这导致典型的可表示值范围介于
-2^N
2^N-1
之间(例如
-32768
32767

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

#包括
#包括
内部主(空){
符号int x,y;
x=整数分钟;
y=x*-1;
printf(“%d\n%d\n”,x,y);
返回0;
}
这导致了以下输出:

# gcc -std=c89 -pedantic int_min_test.c

# ./a.out
-2147483648
-2147483648
我期望出现一个整数溢出(导致典型的值滚动),但似乎没有发生关于
x
-1
相乘的操作

在x86中,
INT\u MIN
-1
的乘法是否是不可操作的?

对于C(基于问题的原始标记,示例代码是用C编写的),它是未定义的行为,因此不,C表达式
INT\u MIN*-1
的结果不是“不可操作的”,它是未定义的行为。在实践中,根据你观察结果的方式,结果很可能是不一致的,甚至可能是暂时不一致的。不要这样做


如果您想询问x86
imul
指令,那是另一个问题,我相信
0x8000000
的(32位)
imul
0xffffff
生成
0x8000000
。但这与您在C中应该看到的内容无关。

使用GCC4.8.5,行
y=x*-1

neg    %eax
neg操作翻转单词的位,然后加1。对于32位2的补码,结果为:

0x80000000 # Start value
0x7FFFFFFF # Flip bits
0x80000000 # Add 1

正如你所看到的,计算机正按照你告诉它的去做。这不是无操作,因为
neg
修改
AF
CF
OF
PF
SF
ZF
标志。它只是正在使用的二进制表示的一个工件。正如其他人所说,这只是未定义的行为

在x86处理器上,将“int”乘以-1的指令将, 当给定位模式0x8000000时,结果产生相同的位模式。 但是,需要注意的是,x86的C编译器可以分为两部分 分为若干类别:

  • 在某些编译器上,所有带符号整数操作的行为都将类似于使用精确长度的本机操作执行数学运算,这相当于以无限精度执行运算,并对任何超出范围的值进行加减,使其进入范围所需的整数模的任何倍数。这种行为与无符号类型类似,只是范围不同。在这样的编译器上,
    -INT\u MIN==INT\u MIN

  • 在某些编译器上,所有带符号整数运算的行为都将如同以无限精度执行一样,但可能会向任何超出范围的值添加或从中减去整数模的任意倍数,可能会产生类似于其类型范围之外的数字的结果。这允许将“x+1>y”之类的表达式替换为“x>=y”,还允许将代码以溢出必须一致包装的方式移出循环之外。在这样的编译器上,
    -INT\u MIN
    可能等于
    INT\u MIN
    ,或者可能等于
    -(long)INT\u MIN
    ,或者任何其他低32位与INT\u MIN匹配的值。一些这样的编译器在将值存储到变量时会截断超出范围的值,但有些可能不会。这种编译器的一个关键特性是,如果在发生溢出的情况下结果的“额外”位不相关,则代码不需要防止溢出[例如,
    uint1=ushort1*ushort2;
    ]

  • 一些编译器将使用整数溢出作为否定时间和因果关系定律的基础。在使用这种编译器时,必须包含逻辑,以不惜一切代价防止溢出,无论由此生成的机器代码是否有助于程序满足要求

  • 就我个人而言,我认为第二种形式的语义最有意义;信息技术 允许在以下情况下进行几乎所有有用的优化: 第三,它使程序员能够实现优化
    在第三种情况下,这是不可能的。如果第二种形式下的行为保证足以确保程序即使在发生溢出时也能满足其行为要求,那么强制程序员处理溢出将降低代码的效率。虽然经常会有这样的情况,溢出检查是一个好主意,即使是以降低效率为代价,但我认为“优化”有些荒谬编译器要求程序员编写的代码效率低于其他需要的代码。

    滚动不是会再次精确地产生尽可能小的值吗?这是未定义的行为(对于2的补码)-与x86没有任何特别的关系。@KerrekSB说了什么。如果你想在没有UB的情况下观察这个问题,只需使用无符号类型。它完全被包装,只需包装到你开始使用的值。这并不是缺乏溢出的证据。是的,我对x86操作码的行为感兴趣。我现在删除了
    C
    标记,以帮助防止混淆。当问题中的代码是C时,仅更改标记并没有真正的帮助。如果您想询问有关asm的信息,请使用asm示例代码。C不直接转换为asm。这是一个很好的观点,在未定义行为的情况下,C实现可以生成任何操作码序列。我将重写一个更好的问题,以便正确地关注x86行为。是的,
    imul
    生成完整的双精度