【问题标题】:Shouldn't 2147483648 + 2147483648 + 2147483648 be -2147483648?2147483648 + 2147483648 + 2147483648 不应该是 -2147483648 吗?
【发布时间】:2020-08-20 20:49:29
【问题描述】:

我正在使用 MSVC 2019,我正在测试一些东西。

感谢很多人,现在我得到了这张照片0

long long a = 2147483648 + 2147483648;
printf("%lld\n", a);

所以这一次,我想'如果我将 2147483648 添加 3 次会怎样?',我做到了。

我认为结果一定是-2147483648,因为2147483648 + 2147483648 + 2147483648等于0 + 2147483648,而02147483648int的值,所以它会是-2147483648

简单来说,我认为前面的代码是这样的:

long long a = (int)2147483648;
printf("%lld\n", a);

但它没有用。这是我写的代码:

long long a = 2147483648 + 2147483648 + 2147483648;
printf("%lld\n", a);

结果是2147483648,不知道为什么。

现在我头晕了哈哈

我做错了什么?

附言文件名是tmp.c

【问题讨论】:

  • @user4581301 但是当我添加 4 次时,比如2147483648 + 2147483648 + 2147483648 + 2147483648,它给了我0,我认为这是正确的答案。
  • 这取决于架构。 long long int 可以与 int64_t 相同,后者可以保持最大值为 9223372036854775807
  • @user4581301 no.. 他正在添加 64 位整数。2147483645 是 32 位,他正在添加 2147483648。如果他做了long long int some_var = 3 * std::numeric_limits<int>::max(),那么他就有 int32 溢出。我将我的声明更改为 can 而不是 is for A long long int is the same.. 很抱歉造成这种混乱。
  • VS-2019 为我显示(2147483648 - 未定义的值,它显示的内容是随机的):rextester.com/AMJ46137 但 clang 和 gcc 和 icc 都显示 6442450944(使用 godbolt.org/z/M7Zeu5 测试) .. 我猜这是一个 msvc 编译器错误,但我不确定。
  • @Brandon,我们都对措辞不当的 cmets 感到内疚。 Hoseong Jeon 的previous question 玩了溢出,他们在这里的预期结果遵循上一个问题的 32 位数学的逻辑。据我所知,您的解释和预期结果是正确的,所以发生了一些有趣的事情。我将退出这个并等待澄清。

标签: c++ c visual-studio visual-studio-2019


【解决方案1】:

在 C 中,遵循 C99 规则,因为 long long 直到那时才出现:

2147483648 不是 32 位 int。它是一个 64 位整数,因为 2147483648 不在 int32_t 正数范围内。

-2147483648 不是 32 位 int。它是一个 64 位整数,因为 2147483648 也不在 int32_t 正数范围内,- 在常量类型形成后应用。

预期的数学输出是 64 位数学的总和。


int main(void) {
  long long a = 2147483648 + 2147483648;
  printf("%lld\n", a);
  a = 2147483648 + 2147483648 + 2147483648;
  printf("%lld\n", a);
  return 0;
}

输出

4294967296
6442450944

OP 报告:

好吧,当我复制你的代码时,我的输出是 0 和 2147483648。

OP 可能正在使用带有 long long 扩展名的 C89 编译器。 visual-studio-2019 不完全符合 C99。示例Does Visual Studio 2017 fully support C99?.
在这种情况下:

C89 使用不同的规则 e.g.:
2147483648 不是 32 位 int。它是一个 32 位的 unsigned long

2147483648 + 2147483648 是无符号溢出,并且明确定义为总和为 0。

2147483648 + 2147483648 + 2147483648,因为 32 位 unsigned long 数学是 32 位 unsigned long 2147483648

将 32 位 unsigned long 2147483648 分配给 long long 是相同的值,不同的类型。


故事的寓意:考虑从所需的结束类型开始计算。

使用下面的代码,左边的类型影响右边的添加。这和Why (not) write 1,000,000,000 as 1000*1000*1000? 是同一个问题

long long a = 2147483648 + 2147483648 + 2147483648;

替代方案:

long long a = (long long) 2147483648 + 2147483648 + 2147483648;

long long a = 0LL + 2147483648 + 2147483648 + 2147483648;

long long a = 2147483648; 
a += 2147483648;
a += 2147483648;

【讨论】:

  • 好吧,当我复制你的代码时,我的输出是 02147483648
  • OP 询问的是 MSVC,而不是标准 C。请参阅他们之前的问题。但是,他们没有为这个问题提供代码,并且不清楚,所以在他们解决这个问题之前应该关闭它。
  • 好的,我会编辑我的问题。你能告诉我应该添加什么吗?
  • @HoseongJeon 我认为人们正在寻找附加到问题的原始代码,您用来确定总和。类似这个答案的东西,但你编码的内容 - 对你来说微小的编码差异可能对其他人很重要。
  • @chux-ReinstateMonica Ahh 明白了。我现在将编辑我的问题。
猜你喜欢
  • 2012-09-19
  • 1970-01-01
  • 2021-02-26
  • 1970-01-01
  • 2017-07-16
  • 2012-06-29
  • 1970-01-01
  • 2011-04-11
相关资源
最近更新 更多