【问题标题】:large negative integer literals大的负整数文字
【发布时间】:2012-01-20 15:32:38
【问题描述】:

在 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 的出色回答。

【问题讨论】:

  • 有趣,这里是反汇编:cout
  • std::cout 的流操作符可能没有像您期望的那样推广这些文字。
  • @ScarletAmaranth 我认为没关系,因为 4294967293 首先被读取为无符号整数,然后被取反,结果为 3。虽然不太确定
  • @drhirsch:他没有使用numeric_limits&lt;int&gt;::min() 他使用的是硬编码文字,这将是编译器默认使用的任何文字。
  • 他把numeric_limits写成cmets来明确编译器使用什么,他的值是正确的

标签: c++


【解决方案1】:

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

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

十进制整型字面量是以下类型中第一个适合其值的类型:

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

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

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

所以给定一个典型的 32 位 2 的补码 int 类型,这样:

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

获取int2147483647,将其取反,并打印与您期望的数学结果相匹配的结果。但是这个:

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

(当使用 gcc 4.6.1 编译时)采用 longunsigned long2147483648,将其取反作为无符号整数,产生 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

int: -2147483648 .. 2147483647
long: -2147483648 .. 2147483647
long long: -9223372036854775808 .. 9223372036854775807
2147483647 is of type int
2147483648 is of type unsigned long
-2147483647 is of type int
-2147483648 is of type unsigned long

我得到与 VS2010 相同的输出,至少在默认设置下。

【讨论】:

  • 但是,正如您刚刚解释的那样,整数文字永远不会是无符号的。 2147483648 应该在这里输入long long
  • @Keith:您自相矛盾:“请注意,它永远不是无符号类型”和“采用无符号 int 值 2147483648”。你能澄清一下吗?
  • @user763305:或者如果是intlongunsigned long,...,我认为这是 gcc 所做的。我想我应该用 VS2010 试试这个。
  • @user763305:与 VS2010 的输出相同。
  • @KeithThompson:如果在编译时在命令行中指定“-std=c++11”或“-std=gnu++11”会怎样? "-std=c99" 有助于处理类似的 C 代码。
【解决方案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 不是一个有效的有符号整数文字,即使它是一个有效的有符号整数值。有人对此有什么想法吗?

【讨论】:

  • -2147483648 根本不是有符号整数文字。 2147483648 是一个整数文字(实际上是常量),- 是一元减号运算符。
  • 可能是因为读作2147483648,它只作为无符号存在,然后取反。
  • @James:谢谢。我不知道- 不是文字的一部分
  • 尝试在编译时在命令行中为 C++ 代码指定“-std=c++11”或“-std=gnu++11”或为 C 代码指定“-std=c99”。这应该会有所帮助(它肯定对 C 有帮助,但我的 C++ 编译器太旧而无法验证)。
猜你喜欢
  • 2020-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多