Проверка за препълване/препълване в C++?

Има ли общ начин за проверка за препълване или недостиг на даден тип данни (uint32, int и т.н.)?

Аз правя нещо подобно:

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

Когато отпечатам a след няколко итерации, той показва голямо число като: 4294963846.


person Legend    schedule 08.03.2010    source източник
comment


Отговори (5)


За да проверите за преливане/понижаване на аритметика, проверете резултата в сравнение с първоначалните стойности.

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

За вас конкретно проверката ще бъде:

if (a > (c-b)) {
    //Underflow
}
person Stephen L    schedule 08.03.2010
comment
това ли е фактът, че в случай на препълване отговорът винаги ще бъде със знак (отрицателно цяло число)? - person Faizan; 24.02.2013
comment
Препълването на цели числа без знак никога няма да бъде подписано, по-скоро ще бъде по-малко цяло число без знак от която и да е от първоначалните стойности. - person Stephen L; 28.02.2013
comment
Внимавайте, подписано препълване е недефинирано поведение в C. - person Alexei Sholik; 05.09.2013

Предполагам, че ако исках да направя това, щях да направя клас, който симулира типа данни, и да го направя ръчно (което би било бавно, предполагам)

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...

Направих подобно нещо с указатели, за да проверя къде паметта се записва извън границите. много бавен, но откри къде паметта е повредена

person matt    schedule 08.03.2010
comment
Има версия на това наречена SafeInt, за която научих тази вечер. Вероятно не е лоша идея да използвате нещо подобно през повечето време, просто не в критичния за производителността код. - person HostileFork says dont trust SE; 17.06.2012

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 ) 
person Shafik Yaghmour    schedule 24.04.2014

Boost има чиста библиотека, наречена Safe Numerics. В зависимост от начина, по който създавате безопасен шаблон, библиотеката ще хвърли изключение, когато възникне препълване или препълване. Вижте https://www.boost.org/doc/libs/1_74_0/libs/safe_numerics/doc/html/index.html.

person Angel E.    schedule 03.05.2021

Ще поставя тук друг възможен подход, в случай че е наличен по-голям (размер 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';
}
person MatG    schedule 04.05.2021