在C++中检查下溢/上溢?

14

有没有一种通用的方法来检查给定数据类型(uint32、int等)是否溢出或下溢?

我正在做这样的事情:

uint32 a,b,c;
... //initialize a,b,c
if(b < c) {
   a -= (c - b)
}

在我迭代若干次后输出 a 时,它显示一个很大的数值,例如:4294963846。


如何在C/C++中检测整数溢出? - phuclv
5个回答

11

要检查算术运算的溢出/下溢,请将结果与原始值进行比较。

uint32 a,b;
//assign values
uint32 result = a + b;
if (result < a) {
    //Overflow
}

针对你的情况,检查的方法如下:

if (a > (c-b)) {
    //Underflow
}

在溢出的情况下,答案总是有符号的(负整数),这是事实吗? - Faizan
1
无符号整数的溢出永远不会被标记为有符号,而是会变成比原始值小的无符号整数。 - Stephen L
2
注意,在C语言中,有符号整数溢出是未定义的行为。 - Alexei Sholik

4

我想,如果我想要做到这一点,我会创建一个模拟数据类型的类,并手动完成它(这可能会很慢)。

class MyInt
{
     int val;
     MyInt(const int&nval){ val = nval;} // cast from int
     operator int(){return val;} // cast to int

    // then just overload ALL the operators... putting your check in
};

//typedef int sint32;
typedef MyInt sint32;

这可能比那更棘手,你可能需要使用定义而不是typedef...

我用指针做了类似的事情,检查内存是否被写在边界之外。虽然很慢,但确实找到了内存损坏的位置。


这里有一个叫做SafeInt的版本(http://safeint.codeplex.com/),我今晚了解到了它。大多数情况下使用这样的东西可能不是个坏主意,只是在性能关键代码中不要使用。 - HostileFork says dont trust SE

3
Cert有一个很好的参考,既包括未定义行为的有符号整数溢出,也包括不是未定义行为的无符号包装,并且涵盖了所有运算符。
该文档提供了以下检查代码,用于使用前提条件进行无符号减法包装:
void func(unsigned int ui_a, unsigned int ui_b) {
  unsigned int udiff;
  if (ui_a < ui_b){
    /* Handle error */
  } else {
    udiff = ui_a - ui_b;
  }
  /* ... */
}

并且带有后置条件:

void func(unsigned int ui_a, unsigned int ui_b) {
  unsigned int udiff = ui_a - ui_b;
  if (udiff > ui_a) {
    /* Handle error */
  }
  /* ... */
}

如果您使用的是gcc 5,您可以使用__builtin_sub_overflow

__builtin_sub_overflow( ui_a, ui_b, &udiff ) 

0

如果有一个更大的(x2大小)整数类型可用,我将在此处提供另一种可能的方法。在这种情况下,可以通过稍微增加计算量来防止溢出发生。

// https://gcc.godbolt.org/z/fh9G6Eeah
#include <exception>
#include <limits>
#include <iostream>

using integer_t = uint32_t; // The desired type
using bigger_t = uint64_t; // Bigger type

constexpr integer_t add(const integer_t a, const integer_t b)
   {
    static_assert(sizeof(bigger_t)>=2*sizeof(integer_t));
    constexpr bigger_t SUP = std::numeric_limits<integer_t>::max();
    constexpr bigger_t INF = std::numeric_limits<integer_t>::min();
    // Using larger type for operation
    bigger_t res = static_cast<bigger_t>(a) + static_cast<bigger_t>(b);
    // Check overflows
    if(res>SUP) throw std::overflow_error("res too big");
    else if(res<INF) throw std::overflow_error("res too small");
    // Back to the original type
    return static_cast<integer_t>(res); // No danger of narrowing here
   }


//---------------------------------------------------------------------------
int main()
{
    std::cout << add(100,1) << '\n';
    std::cout << add(std::numeric_limits<integer_t>::max(),1) << '\n';
}

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接