如何在C中检测整数溢出[重复]

92vpleto  于 2023-04-29  发布在  其他
关注(0)|答案(3)|浏览(130)

此问题已在此处有答案

Detecting signed overflow in C/C++(13个回答)
How do I detect unsigned integer overflow?(30个答案)
4年前关闭。
我们知道CPython在整数变大时会将整数提升为长整数(允许任意精度的算术)。
如何在纯C中检测intlong long的溢出?

jbose2ul

jbose2ul1#

您无法 * 检测 * 有符号int溢出。你必须写代码来避免它。
Signed int overflow是Undefined Behaviour,如果它出现在你的程序中,程序是无效的,编译器不需要生成任何特定的行为。

xam8gpfp

xam8gpfp2#

您可以预测signed int overflow,但尝试在求和后检测它为时已晚。在执行有符号加法之前,必须测试可能的溢出。
在求和后通过测试来避免未定义的行为是不可能的。如果加法溢出,则已经存在未定义的行为。
如果是我,我会这样做:

#include <limits.h>

int safe_add(int a, int b) 
{
    if (a >= 0) {
        if (b > (INT_MAX - a)) {
            /* handle overflow */
        }
    } else {
        if (b < (INT_MIN - a)) {
            /* handle underflow */
        }
    }
    return a + b;
}

有关详细信息,请参阅此paper。在同一篇文章中,你还可以找到为什么无符号整数溢出不是未定义行为,以及什么可能是可移植性问题。

编辑:

GCC和其他编译器有一些规定来检测溢出。例如,GCC具有以下内置函数,允许执行简单的算术运算并检查操作是否溢出。

bool __builtin_add_overflow (type1 a, type2 b, type3 *res)
bool __builtin_sadd_overflow (int a, int b, int *res)
bool __builtin_saddl_overflow (long int a, long int b, long int *res)
bool __builtin_saddll_overflow (long long int a, long long int b, long long int *res)
bool __builtin_uadd_overflow (unsigned int a, unsigned int b, unsigned int *res)
bool __builtin_uaddl_overflow (unsigned long int a, unsigned long int b, unsigned long int *res)
bool __builtin_uaddll_overflow (unsigned long long int a, unsigned long long int b, unsigned long long int *res)

访问link

编辑:

关于某人提出的问题
我认为,解释为什么signed int overflow undefined,而unsigned显然不是。.
答案取决于编译器的实现。大多数C实现(编译器)只是使用任何溢出行为最容易实现的整数表示。
在实践中,有符号值的表示可以不同(根据实现):one's complementtwo's complementsign-magnitude。对于无符号类型,标准没有理由允许变化,因为只有一个明显的binary representation(标准只允许二进制表示)。

7qhs6swi

7qhs6swi3#

在执行加法之前,必须测试有符号操作数。下面是一个安全的加法函数,在所有情况下都有2个比较:

#include <limits.h>

int safe_add(int a, int b) {
    if (a >= 0) {
        if (b > INT_MAX - a) {
            /* handle overflow */
        } else {
            return a + b;
        }
    } else {
        if (b < INT_MIN - a) {
            /* handle negative overflow */
        } else {
            return a + b;
        }
    }
}

如果已知long long类型的范围比int类型的范围大,则可以使用这种方法,这种方法可能会更快:

#include <limits.h>

int safe_add(int a, int b) {
    long long res = (long long)a + b;
    if (res > INT_MAX || res < INT_MIN) {
        /* handle overflow */
    } else {
        return (int)res;
    }
}

相关问题