什么时候需要检查整数溢出

When do I have to check for integer overflow?

本文关键字:整数 溢出 检查 什么时候      更新时间:2023-10-16

我一直在研究整数溢出,最后我创建了一个函数来检查整数溢出和下溢:

#include <exception>
#include <limits>
int safe_add(int a, int b) {
    if (a > 0 && b > INT_MAX - a) {
        throw std::exception("Integer overflow");
    } else if (a < 0 && b < INT_MIN - a) {
        throw std::exception("Integer underflow");
    }
    return a + b;
}

我担心可能出现的性能问题,所以我做了下一个基准测试:

#include <iostream>
#include <exception>
#include <limits>
#include <chrono>
#include <string>
int safe_add(int a, int b) {
    if (a > 0 && b > INT_MAX - a) {
        throw std::exception("Integer overflow");
    } else if (a < 0 && b < INT_MIN - a) {
        throw std::exception("Integer underflow");
    }
    return a + b;
}
void bench_add() {
    for (int i = INT16_MIN; i < INT16_MAX; i++) {
        for (int j = INT16_MIN; j < INT16_MAX; j++) {
            volatile int x = i + j; //I make it volatile so the compiler doesn't optimize it out
        }
    }
}
void bench_safe_add() {
    for (int i = INT16_MIN; i < INT16_MAX; i++) {
        for (int j = INT16_MIN; j < INT16_MAX; j++) {
            volatile int x = safe_add(i, j); //I make it volatile so the compiler doesn't optimize it out
        }
    }
}
void bench_safe_add_with_try() {
    try {
        for (int i = INT16_MIN; i < INT16_MAX; i++) {
            for (int j = INT16_MIN; j < INT16_MAX; j++) {
                volatile int x = safe_add(i, j); //I make it volatile so the compiler doesn't optimize it out
            }
        }
    } catch (std::exception& e) {
        std::cout << e.what() << std::endl;
    }
}
void chrono(const std::string& name, void function(void)) {
    using namespace std::chrono;
    milliseconds start = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
    function();
    long long time = (duration_cast<milliseconds>(system_clock::now().time_since_epoch()) - start).count();
    std::cout << name << ": " << time << "ms" << std::endl;
}
int main() {
    chrono("Standard add", bench_add);
    chrono("Safe add", bench_safe_add);
    chrono("Safe add surrounded by try block", bench_safe_add_with_try);
    system("PAUSE");
    return 0;
}

在我的机器(i7-6700K@4GHZ 16gb RAM)中产生如下输出:

Standard add: 1341ms
Safe add: 13667ms
Safe add surrounded by try block: 13544ms

如果我先用try块调用函数,那么安全添加时间会下降很多。也许是为了分支预测?

关键是,safe_add似乎比简单的添加要慢得多,所以我应该什么时候检查整数溢出?或者何时NOT检查整数溢出?对每个用户输入都使用它是否很重要,或者程序应该崩溃吗?当领导数据库时,性能影响要大得多,因为它需要另一个查询?

谢谢你,佩德罗。

@nikitoz已经给出了我想要的答案:

永远不需要检查整数溢出。验证用户输入对于一些真实世界的检查,如果您需要,请使用long long类型期望大整数,使用特殊的类来处理非常大的整数如果你真的需要,什么尺寸都行(通常不是)。程序不会整数溢出导致崩溃

因此我将其标记为已回答