-2147483648是具有32位的整数类型的最小整数,但它似乎会在if(...)
句子中溢出:
if (-2147483648 > 0)
std::cout << "true";
else
std::cout << "false";
Run Code Online (Sandbox Code Playgroud)
这将true
在我的测试中打印出来.但是,如果我们将-2147483648转换为整数,结果将是不同的:
if (int(-2147483648) > 0)
std::cout << "true";
else
std::cout << "false";
Run Code Online (Sandbox Code Playgroud)
这将打印false
.
我糊涂了.谁能对此作出解释?
更新02-05-2012:
感谢您的评论,在我的编译器中,int的大小是4个字节.我正在使用VC进行一些简单的测试.我在我的问题中改变了描述.
这篇文章中有很多非常好的回复,AndreyT对编译器在这样的输入上的行为以及如何实现这个最小整数给出了非常详细的解释.另一方面,qPCR4vir给出了一些相关的"好奇心"以及如何表示整数.太棒了!
AnT*_*AnT 387
-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)
Run Code Online (Sandbox Code Playgroud)
而不是看似更直接的
#define INT_MIN -2147483648
Run Code Online (Sandbox Code Playgroud)
后者无法按预期工作.
qPC*_*vir 43
编译器(VC2012)提升到可以保存值的"最小"整数.在第一种情况下,signed int
(和long int
)不能(在符号应用之前),但unsigned int
可以:2147483648
hasunsigned int
???? 类型.在第二个你迫使int
从unsigned
.
const bool i= (-2147483648 > 0) ; // --> true
Run Code Online (Sandbox Code Playgroud)
警告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
Run Code Online (Sandbox Code Playgroud)
2.14.2整数文字[lex.icon]
...
整数文字是一系列没有句点或指数部分的数字.整数文字可以具有指定其基数的前缀和指定其类型的后缀.
...
整数文字的类型是相应列表中可以表示其值的第一个.
如果整数文字不能由其列表中的任何类型表示,并且扩展整数类型(3.9.1)可以表示其值,则它可能具有该扩展整数类型.如果文字列表中的所有类型都已签名,则应对扩展整数类型进行签名.如果文字列表中的所有类型都是无符号的,则扩展整数类型应为无符号.如果列表包含有符号和无符号类型,则扩展整数类型可以是有符号或无符号的.如果某个程序的翻译单元中包含一个无法用任何允许类型表示的整数文字,则该程序格式不正确.
这些是标准中整数的促销规则.
4.5整体促销 [conv.prom]
以外的整数类型的prvalue
bool
,char16_t
,char32_t
,或wchar_t
,其整数转换秩(4.13)小于INT的秩可以被转换成类型的prvalueint
如果int
可以表示源类型的所有值; 否则,源prvalue可以转换为类型的prvalueunsigned int
.
因为-2147483648
实际上应用了2147483648
否定 ( -
),所以该数字不是您所期望的。它实际上相当于这个伪代码:operator -(2147483648)
现在,假设您的编译器等于sizeof(int)
并4
定义CHAR_BIT
为8
,这将使2147483648
整数 ( 2147483647
) 的最大有符号值溢出。那么最大加一是多少呢?让我们用 4 位 2 补码整数来解决这个问题。
等待!8 整数溢出!我们做什么?使用其无符号表示1000
并将这些位解释为有符号整数。这种表示法让我们-8
应用 2s 补码否定8
,得到 ,众所周知,它大于0
。
这就是为什么<limits.h>
( 和<climits>
) 通常定义INT_MIN
为((-2147483647) - 1)
- ,以便最大有符号整数 ( 0x7FFFFFFF
) 被取反 ( 0x80000001
),然后递减 ( 0x80000000
)。