大的负整数文字

时间:2011-12-14 21:02:30

标签: c++

在Visual Studio 2010上使用以下程序

#include <iostream>
using std::cout;

int main()
{
    cout << -2147483646 << '\n';
    cout << -2147483647 << '\n';
    cout << -2147483648 << '\n';    // numeric_limits<int>::min()
    cout << -2147483649 << '\n';
    cout << -2147483650 << '\n';
    cout << "..." << '\n';
    cout << -4294967293 << '\n';
    cout << -4294967294 << '\n';
    cout << -4294967295 << '\n';    // -numeric_limits<unsigned int>::max()
    cout << -4294967296 << '\n';
    cout << -4294967297 << '\n';
}

生成以下输出

-2147483646
-2147483647
2147483648
2147483647
2147483646
...
3
2
1
-4294967296
-4294967297

发生了什么事?

这是标准行为还是Visual Studio错误?

编辑:正如有几个人所指出的,没有负整数文字这样的东西。有关详细信息,请参阅下面的Keith Thompson的优秀答案。

2 个答案:

答案 0 :(得分:16)

例如,

-2147483648不是整数文字;它是一个由应用于文字-的一元2147483648运算符组成的表达式。

在新的C ++ 2011标准之前,C ++不要求存在任何大于32位的类型(C ++ 2011添加long long),因此文字2147483648是不可移植的

十进制整数文字是其值适合的以下第一种类型:

int
long int
long long int (new in C++ 2011)

请注意,它从来不是标准C ++中的无符号类型 。在C标准的1998和2003版本(没有long long int)中,一个太大而不适合long int的十进制整数文字会导致未定义的行为。在C ++ 2011中,如果十进制整数文字不适合long long int,则程序“格式错误”。

但是gcc(至少从版本4.6.1开始,我拥有的最新版本)没有实现C ++ 2011语义。文字2147483648,不适合32位长,被视为unsigned long,至少在我的32位系统上。 (这对于C ++ 98或C ++ 2003来说很好;行为是未定义的,因此编译器可以做任何喜欢的事情。)

所以给定一个典型的32位二进制补码int类型,这个:

cout << -2147483647 << '\n';

int2147483647,否定它,并打印出与您期望的数学结果相匹配的结果。但是这个:

cout << -2147483648 << '\n';

(使用gcc 4.6.1编译时)取longunsigned long2147483648,将其否定为unsigned int ,产生{{1打印那个。

正如其他人所提到的,您可以使用后缀来强制使用特定类型。

这是一个小程序,可用于显示编译器如何处理文字:

2147483648

当我编译它时,我收到一些警告:

#include <iostream>
#include <climits>

const char *type_of(int)                { return "int"; }
const char *type_of(unsigned int)       { return "unsigned int"; }
const char *type_of(long)               { return "long"; }
const char *type_of(unsigned long)      { return "unsigned long"; }
const char *type_of(long long)          { return "long long"; }
const char *type_of(unsigned long long) { return "unsigned long long"; }

int main()
{
    std::cout << "int: " << INT_MIN << " .. " << INT_MAX << "\n";
    std::cout << "long: " << LONG_MIN << " .. " << LONG_MAX << "\n";
    std::cout << "long long: " << LLONG_MIN << " .. " << LLONG_MAX << "\n";

    std::cout << "2147483647 is of type " << type_of(2147483647) << "\n";
    std::cout << "2147483648 is of type " << type_of(2147483648) << "\n";
    std::cout << "-2147483647 is of type " << type_of(-2147483647) << "\n";
    std::cout << "-2147483648 is of type " << type_of(-2147483648) << "\n";
}

以及以下输出,即使是lits.cpp:18:5: warning: this decimal constant is unsigned only in ISO C90 lits.cpp:20:5: warning: this decimal constant is unsigned only in ISO C90

gcc -std=c++0x

我使用VS2010获得相同的输出,至少使用默认设置。

答案 1 :(得分:2)

当我在GCC中编译它时,我收到以下消息:

warning: this decimal constant is unsigned only in ISO C90 [enabled by default]

在(包括)

之后的每一行都会发生
cout << -2147483648 << '\n';    // numeric_limits<int>::min()

所以正在发生的事情是Visual Studio的编译器和GCC允许我们编写这些文字,他们只是将它们视为标记为无符号。这解释了打印内容的行为,这使我非常确信输出是正确的(假设我们在数字上放置了u后缀)。

我仍然觉得有趣的是-2147483648不是有效的有符号整数文字,即使它是有效的有符号整数值。对那个人有什么想法吗?