gpt4 book ai didi

c++ - 在 C/C++ 中检测有符号溢出

转载 作者:太空宇宙 更新时间:2023-11-04 13:03:38 28 4
gpt4 key购买 nike

乍一看,这个问题似乎与 How to detect integer overflow? 重复, 但实际上有很大不同。

我发现虽然检测无符号整数溢出非常简单,但在 C/C++ 中检测有符号溢出实际上比大多数人想象的要困难。

最明显但最幼稚的方法是:

int add(int lhs, int rhs)
{
int sum = lhs + rhs;
if ((lhs >= 0 && sum < rhs) || (lhs < 0 && sum > rhs)) {
/* an overflow has occurred */
abort();
}
return sum;
}

这个问题是,根据 C 标准,有符号整数溢出是未定义的行为。换句话说,根据标准,一旦你导致有符号溢出,你的程序就像您取消引用空指针一样无效。所以你不能导致未定义的行为,然后尝试在事后检测溢出,如上面的后置条件检查示例。

尽管上述检查可能适用于许多编译器,但您不能指望它。事实上,因为 C 标准说有符号整数溢出是未定义的,一些编译器(如 GCC)将 optimize away the above check当设置优化标志时,因为编译器假定有符号溢出是不可能的。这完全打破了检查溢出的尝试。

因此,另一种检查溢出的可能方法是:

int add(int lhs, int rhs)
{
if (lhs >= 0 && rhs >= 0) {
if (INT_MAX - lhs <= rhs) {
/* overflow has occurred */
abort();
}
}
else if (lhs < 0 && rhs < 0) {
if (lhs <= INT_MIN - rhs) {
/* overflow has occurred */
abort();
}
}

return lhs + rhs;
}

这看起来更有希望,因为在我们事先确定执行这样的加法不会导致溢出之前,我们实际上并没有将两个整数相加。因此,我们不会导致任何未定义的行为。

但是,不幸的是,这个解决方案的效率比最初的解决方案低很多,因为您必须执行减法运算只是为了测试您的加法运算是否有效。即使您不关心这个(小的)性能影响,我仍然不完全相信这个解决方案是足够的。表达式 lhs <= INT_MIN - rhs看起来完全像是编译器可能优化掉的那种表达式,认为有符号溢出是不可能的。

那么这里有没有更好的解决方案呢?保证 1) 不会导致未定义的行为,以及 2) 不会为编译器提供优化溢出检查的机会?我在想可能有某种方法可以通过将两个操作数都转换为无符号,并通过滚动您自己的补码算法来执行检查,但我不太确定该怎么做。

最佳答案

不,你的第二个代码不正确,但你很接近:如果你设置

int half = INT_MAX/2;
int half1 = half + 1;

加法的结果是INT_MAX . (INT_MAX 始终是奇数)。所以这是有效的输入。但是在你的日常工作中你会有 INT_MAX - half == half1你会中止。误报。

这个错误可以通过输入 < 来修复而不是 <=在两张支票中。

但是您的代码也不是最佳的。可以执行以下操作:

int add(int lhs, int rhs)
{
if (lhs >= 0) {
if (INT_MAX - lhs < rhs) {
/* would overflow */
abort();
}
}
else {
if (rhs < INT_MIN - lhs) {
/* would overflow */
abort();
}
}
return lhs + rhs;
}

要证明这是有效的,您必须象征性地添加 lhs在不等式的两边,这给了你结果超出范围的算术条件。

关于c++ - 在 C/C++ 中检测有符号溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43266510/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com