【问题标题】:Integer overflow in boolean expressions布尔表达式中的整数溢出
【发布时间】:2015-10-27 19:59:08
【问题描述】:

我有以下 c++ 代码:

#include <iostream>

using namespace std;

int main()
{
    long long int currentDt = 467510400*1000000;
    long long int addedDt = 467510400*1000000;
    if(currentDt-addedDt >= 0 && currentDt-addedDt <= 30*24*3600*1000000)
    {
                cout << "1" << endl;
                cout << currentDt-addedDt << endl;

    }       
    if(currentDt-addedDt > 30*24*3600*1000000 && currentDt-addedDt <= 60*24*3600*1000000)
    {
                cout << "2" << endl;
                cout << currentDt-addedDt << endl;

    }       
    if(currentDt-addedDt > 60*24*3600*1000000 && currentDt-addedDt <= 90*24*3600*1000000)
    {
                cout << "3" << endl;
                cout << currentDt-addedDt << endl;

    }       

   return 0;
}

首先,我收到一个整数溢出警告,这让我觉得很奇怪,因为数字 467510400*1000000 正好落在 long long int 的范围内,不是吗?其次,我得到以下输出:

1
0
3
0

如果在这两种情况下 currentDt-addedDt 的计算结果都为 0,那么第三个 if 语句怎么可能计算结果为 true?

【问题讨论】:

  • 如果你使用467510400ll * 1000000ll等会发生什么?也许编译器将它们相乘为ints。
  • long long int,是的,但是所有这些常数的数学运算很可能以int

标签: c++ overflow boolean-logic boolean-expression


【解决方案1】:

467510400*1000000long long 的范围内,但不在int 的范围内。因为这两个字面量都是int 类型,所以产品的类型也是int 类型——这会溢出。仅仅因为您将结果分配给 long long 并不会更改分配的值。出于同样的原因:

double d = 1 / 2;

d 将保留 0.0 而不是 0.5

您需要将其中一个文字显式转换为更大的整数类型。例如:

long long int addedDt = 467510400LL * 1000000;

【讨论】:

  • 这是有道理的。我也必须对 if 语句本身中的文字做同样的事情,对吧? @巴里
  • @Danzo 为什么不将它们存储在const long long 变量中并使用它们呢?
【解决方案2】:
   long long int currentDt = 467510400ll*1000000ll;
   long long int addedDt = 467510400ll*1000000ll;

注意数字后面的两个小写字母“l”。这些使你的常数很长。 C++ 通常将源代码中的数字字符串解释为纯 ints。

【讨论】:

    【解决方案3】:

    您遇到的问题是您的所有整数文字都是int。当您将它们相乘时,它们会溢出,从而给您带来意想不到的行为。要更正此问题,您可以使用 467510400ll * 1000000ll 将它们设为 long long 文字

    【讨论】:

      【解决方案4】:

      因为

      60*24*3600*1000000 evaluates to -25526272
      

      使用

      60LL*24LL*3600LL*1000000LL
      

      改为(注意“LL”后缀)

      【讨论】:

      • 不必评估。
      • @NeilKirk 它在 VS2012 调试器中的作用
      • 有符号整数溢出未定义
      • 也可以使用 64 位 int 编译器。
      • @NeilKirk,是的,但 C++ 中的标准默认整数类型(不带后缀说明符)是 int 而不是 int64。因此,所发布的文字计算将使用int 进行评估,因此会溢出
      【解决方案5】:

      你已经用 C++ 标记了它。

      我对您的代码的最小更改是使用 c++ static_cast 将(任何溢出生成表达式的)文字数字中的至少一个提升为 int64_t(在包含文件 cstdint 中找到)。

      例子:

      //          0         true
      if(currentDt-addedDt  >= 0     
      
      &&   // true because vvvv
      
      //          0        true
         currentDt-addedDt <= 30*24*3600*static_cast<int64_t>(1000000))
      //                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      

      (对于测试 1,if 子句的结果为真。 测试 2 和 3 为假)

      在找到 static_cast 后,编译器将其他 3 个整数(在子句中)提升为 int64_t,因此不会生成有关溢出的警告。

      是的,它添加了很多字符,在某种意义上,“最小”。

      【讨论】:

      • 而且我不反对 LL 后缀,但也许这些字面常量用在了别处,不需要比它们声明的大。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 2019-11-07
      • 2021-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多