(-2147483648> 0)在C ++中返回true?

问题描述 投票:240回答:4

-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月5日:

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

[在这篇文章中有很多很好的答复,AndreyT对编译器将如何对此类输入进行操作以及如何实现此最小整数进行了非常详细的解释。另一方面,qPCR4vir提供了一些相关的“好奇心”以及如何表示整数。太棒了!

c++ integer-overflow
4个回答
390
投票

-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

后者将无法按预期工作。

编译器(VC2012)提升为可以容纳值的“最小”整数。在第一种情况下,signed int(和long int)不能(在应用符号之前),但是unsigned int可以:2147483648具有unsigned int

????类型。在第二秒钟,您从int强制unsigned
const bool i= (-2147483648 > 0) ;  //   --> true

警告C4146:一元减运算符应用于unsigned type

,结果仍然unsigned

这里是相关的“好奇心”:

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 standard

2.14.2整数文字[lex.icon]

整数文字是没有句号或指数部分。整数文字可能具有指定其整数的前缀base和一个指定其类型的后缀。

整数文字的类型是相应列表的第一个可以表示其值。

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9GSUhBWi5wbmcifQ==” alt =“在此处输入图像说明”>

如果整数文字不能用其列表中的任何类型表示并且扩展整数类型(3.9.1)可以表示其值,它可以具有扩展的整数类型。如果列表中的所有类型为如果文字是带符号的,则扩展整数类型应带符号。如果文字列表中的所有类型都是无符号的,扩展整数类型应为无符号。如果列表同时包含有符号和无符号类型,扩展整数类型可以是有符号或未签名。如果程序的翻译单元之一,则格式不正确包含一个整数文字,不能用任何允许的类型。

这些是标准中整数的促销规则。

4.5整体促销

[conv.prom]

boolchar16_tchar32_twchar_t,其整数转换排名(4.13)小于如果int可以表示全部,则可以将int转换为int类型的prvalue源类型的值;否则,源prvalue可以是转换为unsigned int

类型的prvalue

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

[This是二进制形式的2147483648外观。

此外,在带符号二进制计算的情况下,最高有效位(“ MSB”)是符号位。 This question可能有助于解释原因。

因为-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)取反(0x80000001),然后递减(0x80000000) 。


43
投票

编译器(VC2012)提升为可以容纳值的“最小”整数。在第一种情况下,signed int(和long int)不能(在应用符号之前),但是unsigned int可以:2147483648具有unsigned int


7
投票

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


4
投票

因为-2147483648实际上是应用了负号(2147483648)的-,所以该数字不是您所期望的。它实际上等效于此伪代码:operator -(2147483648)

© www.soinside.com 2019 - 2024. All rights reserved.