【发布时间】:2020-01-29 17:45:58
【问题描述】:
我目前正在为 C++ 开发一个安全的整数库。我在实现减法时遇到了一些问题。
下面是我的开头:
#include <limits>
#include <stdexcept>
template<typename I>
class safe_int
{
I val;
public:
typedef I value_type;
static constexpr I max = std::numeric_limits<I>::max();
static constexpr I min = std::numeric_limits<I>::min();
safe_int(I i) : val { i } { };
safe_int &operator+=(I rhs)
{
if( val > 0 && rhs > max - val )
throw std::overflow_error("");
else if( val < 0 && rhs < min - val )
throw std::underflow_error("");
val += rhs;
return *this;
}
};
我第一次尝试这样写operator-=:
safe_int &operator-=(I rhs)
{
return operator+=(-rhs);
}
但显然这将在二进制补码系统上输入-0x80000000 失败。
然后我尝试这样做:
safe_int &operator-=(I rhs)
{
if(rhs < -max)
throw std::overflow_error("");
return operator+=(-rhs);
}
但这不适用于小于0(例如-1 - -0x80000000 应该是0x7fffffff,而是报告溢出)。
然后我尝试了这个:
safe_int &operator-=(I rhs)
{
if( rhs < -max && val > 0 )
throw std::overflow_error("");
return operator+=(-rhs);
}
但是现在即使它正确地捕获了会发生溢出的情况,它本身也会在有效情况下导致溢出(例如-1 - -0x80000000,其中- -0x80000000 溢出)。
在这一点上,我认为没有办法在捕获所有极端情况的同时重用添加中的代码。因此,我可能应该为减法编写不同的代码。
如何正确检查减法之前不会发生整数溢出?
这是一个小测试程序:
int main(void)
{
safe_int<int> i = -1;
i -= -2147483648;
return 0;
}
假设没有特定大小的整数。不要依赖未定义的行为。
【问题讨论】:
-
有一些特殊的指令(加法、减法、乘法)可以告知溢出 - 但我怀疑是否有任何可移植的指令。您可以尝试寻找它们。
-
@ALX23z 如您所知,我没有使用程序集,也没有在检查溢出之前添加。我打算让它完全便携。
-
我知道这不是重点,但你检查过boost.org/doc/libs/develop/libs/safe_numerics 吗?
-
@Tarc 我不使用 Boost。安装一个巨大的库是一件很痛苦的事情,否则会很简单。
-
是的,但至少它是经过策划的,而且我认为 Safe Numerics 旨在便于携带。也许值得一读,看看作者使用的技术。
标签: c++ integer subtraction integer-overflow