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

时间:2016-08-25 13:48:54

标签: c++ integer-overflow

我一直在研究整数溢出,我结束创建了一个检查整数溢出和下溢的函数:

#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 检查整数溢出?在每个用户输入中使用它或者程序是否崩溃是否重要?当领导数据库时,性能影响要大得多,因为它需要另一个查询?

谢谢你,Pedro。

1 个答案:

答案 0 :(得分:0)

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

  

您永远不需要检查整数溢出。验证用户输入   反对一些理智的现实世界检查,如果你使用长长型   期望大整数,使用特殊类来表示非常大的整数   如果你真的需要它(通常不是),无论大小。程序不会   因整数溢出而崩溃。

所以我将此标记为已回答