(-2147483648> 0)在C ++中返回true?
-2147483648是32位整数types的最小整数,但它似乎会在if(...)
语句中溢出:
if (-2147483648 > 0) std::cout << "true"; else std::cout << "false";
这将在我的testing中打印出来。 但是,如果我们将-2147483648转换为整数,结果将会不同:
if (int(-2147483648) > 0) std::cout << "true"; else std::cout << "false";
这将打印false
。
我很困惑。 任何人都可以对此作出解释吗?
更新02-05-2012:
感谢您的意见,在我的编译器中,int的大小是4个字节。 我正在使用VC进行一些简单的testing。 我改变了我的问题的描述。
在这篇文章中有很多非常好的回复, AndreyT给出了关于编译器如何处理这种input的详细解释,以及这个最小整数是如何实现的。 qPCR4vir另一方面给了一些相关的“好奇心”,以及如何表示整数。 好印象深刻!
-2147483648
不是“数字”。 C ++语言不支持负文字值。
-2147483648
实际上是一个expression式:在它前面带有一元运算符的一个正面的字面值2147483648
。 在您的平台上,值为2147483648
对于int
范围的正面显然太大了。 如果long int
types在你的平台上有更大的范围,编译器将不得不自动假定2147483648
具有long int
types。 (在C ++ 11中,编译器也必须考虑long long int
types)。这会使编译器在更大types的域中计算-2147483648
,结果将是负值,正如人们所期望的那样。
然而,显然在你的情况下, long int
的范围和long int
的范围是一样的,一般来说在你的平台上没有比int
更大的整数types。 这正式意味着正常数2147483648
溢出所有可用的有符号整数types,这又意味着程序的行为是未定义的。 (在这种情况下,语言规范select未定义的行为有点奇怪,而不需要诊断消息,但事实就是这样。)
在实践中,考虑到行为是不确定的, 2147483648
可能会被解释为一些实现依赖的负值,在应用了一元运算后,这个负值会变为正值。 或者,某些实现可能会决定尝试使用无符号types来表示值(例如,在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
可以: 2147483648
有unsigned int
? types。 在第二个你强制int
unsigned
。
const bool i= (-2147483648 > 0) ; // --> true
警告C4146:将一元减号运算符应用于无符号types ,结果仍为无符号
这里有相关的“好奇心”:
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
C ++ 11标准 :
2.14.2整数文字[lex.icon]
…
整数文字是一个没有周期或指数部分的数字序列。 整数字面量可以有一个前缀,用来指定其基数和一个指定其types的后缀。
…
整数字面量的types是其中可以表示其值的对应列表的第一个。
如果整数字面值不能由列表中的任何types表示,并且扩展整数types(3.9.1)可以表示它的值,则它可能具有该扩展整数types。 如果文字列表中的所有types都有符号,则应对扩展整数types进行签名。 如果文字列表中的所有types均为无符号,则扩展整数types应为无符号。 如果列表包含有符号types和无符号types,则扩展整数types可以是有符号的或无符号的。 如果一个程序的某个翻译单元包含一个不能由任何允许的types表示的整数字面值,那么这个程序是不合格的。
这些是标准中整数的促销规则。
4.5积分促销 [conv.prom]
除了
bool
,char16_t
,char32_t
或wchar_t
其整数转换等级(4.13)小于int的等级)的整数types的前值可以被转换为int
types的prvalue,如果int
可以表示源types的所有值; 否则,可以将源prvalue转换为unsigned int
types的prvalue 。
总之, 2147483648
溢出到-2147483648
,和(-(-2147483648) > 0)
为true
。
这是2147483648
在二进制文件中的样子。
另外,在有符号二进制计算的情况下,最高有效位(“MSB”)是符号位。 这个问题可能有助于解释原因。
因为-2147483648
实际上是2147483648
,否定( -
)适用于它,这个数字不是你所期望的。 它实际上相当于这个伪代码: operator -(2147483648)
现在,假设你的编译器的sizeof(int)
等于4
, CHAR_BIT
被定义为8
,这将使2147483648
溢出一个整数( 2147483647
)的最大符号值。 那么最多加一个是多less? 让我们用4位,2s的恭维整数来解决这个问题。
等待! 8溢出整数! 我们做什么? 使用它的无符号表示forms1000
并将这些位解释为有符号整数。 这个表示让我们用-8
来应用二进制补码否定,结果是8
,我们都知道,它大于0
。
这就是为什么<limits.h>
(和<climits>
)通常将INT_MIN
定义为((-2147483647) - 1)
,以便最大有符号整数( 0x7FFFFFFF
)被取反( 0x80000001
),然后递减( 0x80000000
)。