-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
。
我很困惑。有人可以对此作出解释吗?
2012年2月2日更新:
感谢您的评论,在我的编译器中,int的大小是4个字节。我正在使用VC进行一些简单的测试。我在我的问题中改变了描述。
在这篇文章中有很多非常好的回复,AndreyT给出了关于编译器如何在这样的输入上行为以及如何实现这个最小整数的非常详细的解释。另一方面,qPCR4vir给出了一些相关的“好奇心”以及如何表示整数。太棒了!
答案 0 :(得分:385)
-2147483648
不是“数字”。 C ++语言不支持负文字值。
-2147483648
实际上是一个表达式:一个正面的字面值2147483648
,前面有一元-
运算符。对于您平台上2147483648
范围的积极方面,值int
显然太大了。如果类型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
后者不会按预期工作。
答案 1 :(得分:43)
编译器(VC2012)提升为可以保存值的“最小”整数。在第一种情况下,signed int
(和long int
)不能(在应用符号之前),但unsigned int
可以: 2147483648
有unsigned int
< / strong> ????类型。
在第二步中,您从int
强制unsigned
。
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
2.14.2整数文字[lex.icon]
...
整数文字是一个没有句号或数字的数字序列 指数部分。整数文字可以具有指定其的前缀 base和指定其类型的后缀。
...
整数文字的类型是相应列表的第一个 其值可以表示。
如果整数文字无法在其列表中以任何类型表示 并且扩展整数类型(3.9.1)可以表示其值,它可以 有那个扩展的整数类型。如果列表中的所有类型 文字已签名,扩展整数类型应签名。如果 文字列表中的所有类型都是无符号的 扩展整数类型应该是无符号的。如果列表包含两者 有符号和无符号类型,扩展整数类型可以是签名或 无符号。如果其中一个翻译单元,则该程序格式不正确 包含一个不能由任何表示的整数文字 允许的类型。
这些是标准中整数的促销规则。
4.5整体促销 [conv.prom]
除
类型的prvaluebool
,char16_t
,char32_t
以外的整数类型的prvalue,或者wchar_t
,其整数转换等级(4.13)小于等级 如果int
可以表示全部,则可以将int转换为int
类型的prvalue 源类型的值;否则,源prvalue可以 已转换为unsigned int
答案 2 :(得分:7)
简而言之,2147483648
溢出至-2147483648
,(-(-2147483648) > 0)
为true
。
This是2147483648
在二进制文件中的样子。
此外,在有符号二进制计算的情况下,最高有效位(“MSB”)是符号位。 This question可能有助于解释原因。
答案 3 :(得分:4)
由于-2147483648
实际上是2147483648
并且应用了否定(-
),因此该数字不是您所期望的。它实际上相当于这个伪代码:operator -(2147483648)
现在,假设您的编译器sizeof(int)
等于4
且CHAR_BIT
定义为8
,那么2147483648
会溢出最大符号值整数(2147483647
)。那么最大加一个是什么?让我们使用4位,2s的补码整数。
等待! 8溢出整数!我们做什么?使用其无符号表示1000
并将这些位解释为有符号整数。这种表示使我们-8
被应用了2s补语否定,导致8
,我们都知道,这大于0
。
这就是<limits.h>
(和<climits>
)通常将INT_MIN
定义为((-2147483647) - 1)
的原因 - 以便最大有符号整数(0x7FFFFFFF
)被否定({ {1}}),然后递减(0x80000001
)。