C++大量(无符号长长)的溢出检测

C++ overflow detection for large numbers (unsigned long long)

本文关键字:溢出 检测 C++ 无符号 大量      更新时间:2023-10-16

我正在处理大整数(无符号长整型),需要防止溢出情况。无论是否实际存在异常,代码都会引发异常:

try
{
    unsigned long long y = std::numeric_limits<unsigned long long>::max() - 2;
    unsigned long long z = 1;
    int size = - 1;
    if((y+z) ^ y < 0) //If y+z causes overflow its sign will be changed => y and (y+z) will have opposite signs
        throw std::overflow_error("overflow of y+z");
    //int* myarray= new int[size]; VS Debug Library catches it earlier than catch()
    printf("%dn", y*(y+z));
}
catch(exception& e)
{
    cout << e.what() << endl;
}

由于它已经是最大的数据类型(64 位),因此没有空间升级到更大的数据类型。

新代码:

try
{
    unsigned long long int y = std::numeric_limits<unsigned long long int>::max() - 2;
    unsigned long long int z = std::numeric_limits<unsigned long long int>::max() / 2;
    unsigned long long delta = std::numeric_limits<unsigned long long int>::max() - y;
    int size = - 1;
    if(z > delta) //If y+z causes overflow its sign will be changed => y and (y+z) will have opposite signs
        throw std::overflow_error("overflow of y+z");
    //int* myarray= new int[size]; VS Debug Library catches it earlier than catch()
    printf("%dn", (y+z));
}
catch(exception& e)
{
    cout << e.what() << endl;
}

y < 0总是假的,任何 xor 0 将永远是那个东西(您是否错过了<的评估优先级高于 ^

因此,除非 mod x + y <the max value>恰好等于 0,否则您将抛出(并且可能总是在实践中抛出,除非您人为地设计了特定的输入)。

也许你的意思是这样的:if((std::numeric_limits<unsigned long long>::max() - y) < z) throw ...;

您有两个问题。主要是运算符优先级:<高于^。这是在启用所有警告的情况下进行编译的一个很好的原因,因为 gcc 和 clang 都给了我一个关于这个表达式的警告并建议括号!

编译器评估的表达式实际上是:

if ( (y+z) ^ (y < 0) )

由于y < 0的计算结果为 0 ,这只是:

if (y+z)

这显然是true.但即使括号正确,如:

if (((y+z) ^ y) < 0) { ... }

这个表达方式false微不足道。它仍将具有永远不会评估为 < 0unsigned long long 型。