C:标准和编译器中的整数溢出

Cha*_*les 28 c standards gcc undefined

由Carl Norum编辑,包括适当的标准参考.

C标准规定

如果在计算表达式期间发生异常情况(即,如果结果未在数学上定义或未在其类型的可表示值范围内),则行为未定义.

是否有编译器开关可以保证整数溢出时的某些行为?我想避免鼻腔恶魔.特别是,我想强制编译器包装溢出.

为了唯一性,让标准为C99,编译器为gcc.但我会对其他编译器(icc,cl)和其他标准(C1x,C89)的答案感兴趣.事实上,只是为了惹恼C/C++人群,我甚至欣赏C++ 0x,C++ 03和C++ 98的答案.

注:国际标准ISO/IEC 10967-1可能与此相关,但据我所知,仅在资料性附录中提到过.

Mat*_*ner 22

看看-ftrapv-fwrapv:

-ftrapv

此选项为加法,减法,乘法运算的带符号溢出生成陷阱.

-fwrapv

此选项指示编译器假设加法,减法和乘法的带符号算术溢出使用二进制补码表示.此标志启用一些优化并禁用其他优化.默认情况下,Java前端根据Java语言规范的要求启用此选项.

  • 注意`-fwrapv`确实**不保证溢出将换行.它所做的就是告诉优化器它可以*假设*就是这种情况.它是否真的取决于您的机器架构. (12认同)
  • @Charles 对于无符号类型,您不需要它们-已经为它们定义了溢出行为(请参阅我的答案)。 (3认同)

Car*_*rum 14

对于你的C99答案,我认为6.5表达式,第5段是你正在寻找的:

如果在计算表达式期间发生异常情况(即,如果结果未在数学上定义或未在其类型的可表示值范围内),则行为未定义.

这意味着如果你遇到溢出,你就不走运了 - 没有任何保证的行为.无符号类型是一种特殊情况,永不溢出(6.2.5类型,第9段):

涉及无符号操作数的计算永远不会溢出,因为无法通过生成的无符号整数类型表示的结果将以比结果类型可以表示的最大值大1的数量为模.

C++有相同的陈述,措辞有点不同:

  • 5表达,第4段:

    如果在评估表达式期间,结果未在数学上定义或未在其类型的可表示值范围内,则行为未定义.[ 注意:大多数现有的C++实现忽略整数溢出.除零处理,使用零除数形成余数,所有浮点异常因机器而异,通常可通过库函数调整.-endnote ]

  • 3.9.1基本类型,第4段:

    声明的无符号整数unsigned应遵守算术模2 ^ n的定律,其中n是该特定整数大小的值表示中的位数.


AnT*_*AnT 7

在C99中,一般行为以6.5/5表示

如果在计算表达式期间发生异常情况(即,如果结果未在数学上定义或未在其类型的可表示值范围内),则行为未定义.

无符号类型的行为在6.2.5/9中描述,它基本上表明对无符号类型的操作永远不会导致异常条件

涉及无符号操作数的计算永远不会溢出,因为无法通过生成的无符号整数类型表示的结果将以比结果类型可以表示的最大值大1的数量为模.

GCC编译器有一个特殊选项-ftrapv,用于捕获有符号整数操作的运行时溢出.


Vik*_*ist 5

为了完整起见,我想补充一点,Clang 现在有“检查算术内置函数”作为语言扩展。这是使用检查无符号乘法的示例:

unsigned x, y, result;
...
if (__builtin_umul_overflow(x, y, &result)) {
    /* overflow occured */
    ...
}
...
Run Code Online (Sandbox Code Playgroud)

http://clang.llvm.org/docs/LanguageExtensions.html#checked-arithmetic-builtins

  • GCC 现在也有内置的整数溢出。请参阅 https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html。 (2认同)