是否有通用的方法来检查给定数据类型(uint32,int等)的溢出或下溢?
我正在做这样的事情:
uint32 a,b,c;
... //initialize a,b,c
if(b < c) {
a -= (c - b)
}
当我在经过一些迭代后打印时,会显示一个很大的数字,如:4294963846。
答案 0 :(得分:9)
要检查算术中的上溢/下溢,请检查结果与原始值的比较。
uint32 a,b;
//assign values
uint32 result = a + b;
if (result < a) {
//Overflow
}
具体来说,检查将是:
if (a > (c-b)) {
//Underflow
}
答案 1 :(得分: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;
它可能比那更棘手,你可能不得不最后使用define而不是typedef ......
我做了类似的事情,用指针检查内存写在边界的哪一边。非常缓慢,但确实找到了内存被破坏的地方
答案 2 :(得分:3)
Cert对signed integer overflow(未定义的行为)和unsigned wrapping都有很好的参考,但不包括所有运营商。
该文件使用前置条件为减法中的无符号包装提供以下检查代码如下:
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 )
答案 3 :(得分:0)
Boost 有一个简洁的库,称为 Safe Numerics。根据您实例化安全模板的方式,库将在发生溢出或下溢时抛出异常。见https://www.boost.org/doc/libs/1_74_0/libs/safe_numerics/doc/html/index.html。
答案 4 :(得分: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';
}