我如何正确地检查减法之前整数下溢和溢出不会发生?

问题描述 投票:2回答:2

我目前正在为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;
}

假定没有特定大小的整数。不要依赖未定义的行为。

c++ integer subtraction integer-overflow
2个回答
1
投票
template<class I>
bool valid_add( I lhs, I rhs ) {
  static constexpr I max = std::numeric_limits<I>::max();
  static constexpr I min = std::numeric_limits<I>::min();

  if( rhs > 0 && lhs > max - rhs ) return false;
  if( rhs < 0 && lhs < min - rhs ) return false;

  return true;
}
template<class I>
bool valid_subtract( I lhs, I rhs ) {
  static constexpr I max = std::numeric_limits<I>::max();
  static constexpr I min = std::numeric_limits<I>::min();

  if ((rhs < 0) && (lhs > max + rhs)) return false;
  if ((rhs > 0) && (lhs < min + rhs)) return false;

  return true;
}

0
投票

我想补充一点,val >= 0 && rhs < -max还需要检查。这就是我最终得到的结果:

© www.soinside.com 2019 - 2024. All rights reserved.