布尔表达式中的整数溢出
Integer overflow in boolean expressions
我有以下 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 语句怎么可能计算为真?
467510400*1000000
在long long
范围内,但不在int
范围内。由于两个文字都是 int
类型,因此产品的类型也是 int
类型 - 这将溢出。仅仅因为您将结果分配给 long long
不会更改分配的值。出于同样的原因,在:
double d = 1 / 2;
d
将保持 0.0
而不是 0.5
。
您需要将其中一个文字显式转换为更大的整数类型。例如:
long long int addedDt = 467510400LL * 1000000;
long long int currentDt = 467510400ll*1000000ll;
long long int addedDt = 467510400ll*1000000ll;
注意数字后面的两个小写字母 "l"。这些使您的常量变长。 C++ 通常将源代码中的数字串解释为纯 int
s.
您遇到的问题是您所有的整数文字都是 int
。当您将它们相乘时,它们会溢出,从而给您带来意想不到的行为。要更正此问题,您可以使用 467510400ll * 1000000ll
使它们成为 long long
文字
因为
60*24*3600*1000000 evaluates to -25526272
使用
60LL*24LL*3600LL*1000000LL
改为(注意 'LL' 后缀)
你已经用 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,因此不会生成有关溢出的警告。
是的,它添加了很多字符,从某种意义上说,'minimal'。
我有以下 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 语句怎么可能计算为真?
467510400*1000000
在long long
范围内,但不在int
范围内。由于两个文字都是 int
类型,因此产品的类型也是 int
类型 - 这将溢出。仅仅因为您将结果分配给 long long
不会更改分配的值。出于同样的原因,在:
double d = 1 / 2;
d
将保持 0.0
而不是 0.5
。
您需要将其中一个文字显式转换为更大的整数类型。例如:
long long int addedDt = 467510400LL * 1000000;
long long int currentDt = 467510400ll*1000000ll;
long long int addedDt = 467510400ll*1000000ll;
注意数字后面的两个小写字母 "l"。这些使您的常量变长。 C++ 通常将源代码中的数字串解释为纯 int
s.
您遇到的问题是您所有的整数文字都是 int
。当您将它们相乘时,它们会溢出,从而给您带来意想不到的行为。要更正此问题,您可以使用 467510400ll * 1000000ll
long long
文字
因为
60*24*3600*1000000 evaluates to -25526272
使用
60LL*24LL*3600LL*1000000LL
改为(注意 'LL' 后缀)
你已经用 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,因此不会生成有关溢出的警告。
是的,它添加了很多字符,从某种意义上说,'minimal'。