如何在没有未定义行为的情况下检查C中的有符号整数溢出?

Gan*_*ker 26 c integer-overflow

有(1):

// assume x,y are non-negative
if(x > max - y) error;
Run Code Online (Sandbox Code Playgroud)

并且(2):

// assume x,y are non-negative
int sum = x + y;
if(sum < x || sum < y) error;
Run Code Online (Sandbox Code Playgroud)

哪个是首选或有更好的方法.

caf*_*caf 60

整数溢出是C中"未定义行为"的规范示例(注意无符号整数上的操作永远不会溢出,而是定义为环绕式转换).这意味着一旦你执行了x + y,如果它已经溢出,你已经被冲洗了.做任何检查都为时已晚 - 您的程序可能已经崩溃了.可以把它想象为检查除零 - 如果你等到除法执行后再检查,那已经太晚了.

所以这意味着方法(1)是唯一正确的方法.对于max,您可以使用INT_MAX<limits.h>.

如果x和/或y可能是负面的,那么事情就更难了 - 你需要以一种测试本身不会导致溢出的方式进行测试.

if ((y > 0 && x > INT_MAX - y) ||
    (y < 0 && x < INT_MIN - y))
{
    /* Oh no, overflow */
}
else
{
    sum = x + y;
}
Run Code Online (Sandbox Code Playgroud)

  • 将性能与不正确的解决方案进行比较是没有意义的.您有什么其他正确的解决方案? (8认同)
  • 另一种通常的方式似乎是投射到更广泛的类型.我不确定第三种选择,但确实有更多选择. (2认同)

Chr*_*odd 6

你真的只能用unsigned整数和算术来检查溢出:

unsigned a,b,c;
a = b + c;
if (a < b) {
    /* overflow */
}
Run Code Online (Sandbox Code Playgroud)

带有符号整数的溢出行为在C中是未定义的,但在大多数机器上都可以使用

int a,b,c;
a = b + c;
if (c < 0 ? a > b : a < b) {
    /* overflow */
}
Run Code Online (Sandbox Code Playgroud)

这不适用于使用任何饱和算法的机器

  • 使用有符号整数检查溢出后的溢出是不正确的.这是未定义的行为,因此编译器会愉快地优化检查而不通过像`-fwrapv`这样的开关来启用签名包装作为语言扩展.这不仅仅是跨架构的可移植性问题. (8认同)
  • 不,现代 gcc 破坏了您签名的 `int` 示例。[ARM64 上的有符号整数没有溢出?](//stackoverflow.com/q/54510094)。 (2认同)

cla*_*hey -6

您只需检查其中一项即可。如果 x + y 溢出,它将小于 x 和 y。因此:

int sum = x + y;
if (sum < x) error;
Run Code Online (Sandbox Code Playgroud)

应该足够了。

以下站点有很多关于整数溢出的内容:

http://www.fefe.de/intof.html

如果要处理负数,可以扩展:

int sum = x + y;
if (y >= 0) {
   if (sum < x) error;
} else {
   if (sum > x) error;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是不正确的 - 一旦“x + y”溢出,程序就会出现未定义的行为。在实际执行溢出操作之前,您*必须*进行检查 - 就像整数除以零一样。 (21认同)