(-2147483648的在0)在c++中返回true ?

-2147483648是32位整数类型的最小整数,但它似乎会在if(...)语句中溢出:

if (-2147483648 > 0)
std::cout << "true";
else
std::cout << "false";

这将在我的测试中打印true。然而,如果我们将-2147483648转换为整数,结果将不同:

if (int(-2147483648) > 0)
std::cout << "true";
else
std::cout << "false";

这将打印false

我困惑。有人能解释一下吗?


更新02-05-2012:

感谢您的评论,在我的编译器中,int的大小是4字节。我正在使用VC进行一些简单的测试。我改变了问题中的描述。

这篇文章中有很多非常好的回复,AndreyT给出了编译器如何对这样的输入行为的非常详细的解释,以及这个最小整数是如何实现的。另一方面,qPCR4vir给出了一些相关的“奇闻轶事”;以及整数是如何表示的。所以印象深刻!

29094 次浏览

-2147483648不是一个“数字”。c++语言不支持负字面值。

-2147483648实际上是一个表达式:一个正的字面值2147483648,前面是一个一元的-操作符。在你的平台上,对于int范围的正数来说,值2147483648显然太大了。如果类型long int在你的平台上有更大的范围,编译器将不得不自动假设2147483648具有long int类型。(在c++ 11中,编译器还必须考虑long long int类型。)这将使编译器在更大类型的域中计算-2147483648,结果将如预期的那样为负。

然而,显然在你的情况下,long int的范围与int的范围相同,并且通常在你的平台上没有比int范围更大的整数类型。这在形式上意味着正常量2147483648溢出所有可用的有符号整型,这反过来意味着程序的行为是未定义的。(语言规范在这种情况下选择未定义的行为,而不是要求诊断消息,这有点奇怪,但事实就是这样。)

在实践中,考虑到行为是未定义的,2147483648可能会被解释为某个依赖于实现的负值,在应用一元-后恰好变成正值。或者,一些实现可能决定尝试使用无符号类型来表示值(例如,在C89/90编译器中需要使用unsigned long int,但在C99或c++中不需要)。实现可以做任何事情,因为无论如何行为都是未定义的。

顺便说一句,这就是为什么像INT_MIN这样的常量通常被定义为

#define INT_MIN (-2147483647 - 1)

而不是看起来更直接

#define INT_MIN -2147483648

后者不会像预期的那样起作用。

编译器(VC2012)提升到可以保存值的“最小”整数。在第一种情况下,signed int(和long int)不能(在应用符号之前),但unsigned int可以:__ABC3有unsigned int ????类型。 在第二种情况下,你强制intunsigned。< / p >
const bool i= (-2147483648 > 0) ;  //   --> true

警告C4146:一元减号运算符应用于无符号类型,结果仍然是无符号

以下是相关的“好奇心”:

const bool b= (-2147483647      > 0) ; //  false
const bool i= (-2147483648      > 0) ; //  true : result still unsigned
const bool c= ( INT_MIN-1       > 0) ; //  true :'-' int constant overflow
const bool f= ( 2147483647      > 0) ; //  true
const bool g= ( 2147483648      > 0) ; //  true
const bool d= ( INT_MAX+1       > 0) ; //  false:'+' int constant overflow
const bool j= ( int(-2147483648)> 0) ; //  false :
const bool h= ( int(2147483648) > 0) ; //  false
const bool m= (-2147483648L     > 0) ; //  true
const bool o= (-2147483648LL    > 0) ; //  false

11标准c++:

2.14.2整数字面量[lex.icon]

...

整数字面值是一个没有句号或的数字序列 指数的部分。一个整型字面值可以有一个前缀来指定它

. Base和指定类型的后缀

...

整数字面值的类型是对应列表的第一个

enter image description here

如果一个整数字面值不能由其列表中的任何类型表示 扩展的整数类型(3.9.1)可以表示它的值 拥有扩展的整型。如果列表中的所有类型为 字面值是有符号的,扩展的整数类型应该有符号。如果 字面值列表中的所有类型都是无符号的 扩展整数类型应该是无符号的。如果列表包含两者 有符号和无符号类型,扩展整数类型可以是有符号或 无符号。如果一个程序的一个翻译单元是病态的 类型不能表示的整数字面值 允许类型。< / p >

这些是标准中整数的提升规则。

4.5积分推广 [conv.prom]

整数类型的prvalue,而不是boolchar16_tchar32_t或 的整数转换秩(4.13)小于的秩的wchar_t 如果int可以表示所有类型,int可以转换为类型为int的prvalue 源类型的值;否则,源prvalue可以为 转换为类型为unsigned int

的prvalue

简而言之,2147483648溢出到-2147483648,而(-(-2147483648) > 0)true

2147483648的二进制格式。

此外,在有符号二进制计算的情况下,最有效的位(“MSB”)是符号位。这个问题可能有助于解释为什么。

因为-2147483648实际上是2147483648与否定(-)应用于它,这个数字不是你所期望的。它实际上相当于这个伪代码:operator -(2147483648)

现在,假设你的编译器有sizeof(int)等于4并且CHAR_BIT被定义为8,这将使2147483648溢出整数的最大有符号值(2147483647)。所以最大值加1是多少?我们用一个4位2s补整数来算。

等等!8溢出整数!我们该怎么办?使用1000的无符号表示,并将位解释为有符号整数。这种表示留给我们的是-8被应用于2s补的否定,结果是8,我们都知道,它大于0

这就是为什么<limits.h>(和<climits>)通常将INT_MIN定义为((-2147483647) - 1) -以便最大有符号整数(0x7FFFFFFF)被负(0x80000001),然后减去(0x80000000)。