2010-09-09 146 views
26

编辑包含适当的标准参考感谢Carl Norum。C:标准和编译器中的整数溢出

C标准状态

如果表达式的评估(即,如果该结果不是在数学上表示的值的其类型的范围限定或不期间发生异常条件 ),行为是不确定的。

是否有编译器开关保证整数溢出的某些行为?我想避免鼻子恶魔。特别是,我想强制编译器在溢出时换行。

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

注:国际标准ISO/IEC 10967-1在这里可能是相关的,但据我所知,它只在信息附件中提到。

回答

19

看看-ftrapv and -fwrapv

-ftrapv

此选项对加法,减法,乘法运算符号溢出产生的陷阱。

-fwrapv

此选项指示编译器采用加法,减法和乘法的签署算术溢出包装了使用二进制补码表示身边。该标志启用一些优化并禁用其他。根据Java语言规范的要求,该选项默认为Java前端启用。

+1

优秀,正是我想看到的。有没有类似的无符号类型? – Charles 2010-09-09 17:53:27

+0

@Charles你不需要他们的无符号类型 - 溢出行为已经为他们定义好了(请参阅我的答案)。 – 2010-09-09 18:00:29

+0

@Carl Norum:我看到它是用C++定义的,它在C中定义了轮班(6.5.7段5)。我无法看到C标准中添加和乘法的定义。 – Charles 2010-09-09 18:03:34

0

我不确定是否有任何编译器开关可用于强制C/C++中的溢出的统一行为。另一种选择是使用SafeInt<T>模板。这是一个跨平台的C++模板,为所有类型的整型操作提供了确定性的上溢/下溢检查。

13

为了您的C99答案,我想6.5表达式,第5款是你在找什么:

如果在一个异常情况发生评估一个表达式(也就是说,如果结果不是数学上定义的或者不在其类型的可表示值范围内),则行为是未定义的。

这意味着,如果您遇到溢出问题,那么您运气不好 - 没有任何行为可以保证。无符号类型是一种特殊情况,并且永远不会溢出(6.2.5类型,第9段):

涉及无符号的操作数可以永远不会溢出的一种计算,因为不能由所得到的无符号整数类型来表示结果被减少的模数大于可由最终类型表示的最大值的数。

C++有相同的语句,措辞稍有不同:

  • 5表达式,第4段:

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

  • 3.9.1基本类型,第4款:

    无符号整数,宣布unsigned,应当服从算术模的法律2^ň其中ñ是该特定大小整数的值表示中的位数。

+0

是的,这就是我一直在寻找。 (虽然起初引用让我感到困惑 - 这是第6.5段,而不是第6.5.5节。)你知道有什么办法可以避免这种情况吗?在溢出时打包是很常见的事情,并且有很多时候我希望发生这种情况。是否有流行的编译器有一个开关,使他们承诺换行? – Charles 2010-09-09 17:49:23

+0

@Charles,未定义的行为是未定义的。你可能会对你的特定编译器感到幸运 - 检查它的文档以获得一个让你安心的声明。例如,在'gcc'中,可以查看'-fstrict-overflow'和'-fwrapv'标志。 – 2010-09-09 17:52:05

7

在C99的一般行为的表达 (即,如果结果不是评估过程中6.5/5

如果异常条件发生 desribed 在数学上定义或不在 类型的 可表示值范围内),则行为未定义。

无符号类型的行为在6.2.5/9,其基本上指出无符号类型的操作决不会导致异常条件

甲计算溢出涉及无符号的操作数 可以从未描述的,因为一个 结果不能由 所得的无符号整数类型表示是 减小模是比 可以通过将所得 类型表示的最大值大于一个 数。

GCC编译器有一个特殊的选项-ftrapv,它旨在捕获有符号整数运算的运行时溢出。

2

6.2.5条第9款是你在找什么:

有符号整数类型的非负的值的范围是对应的无符号整数类型 的子范围,并表示每个 类型中的相同值都是相同的.31)涉及无符号操作数的计算永远不会溢出,因为无法用结果无符号整数类型表示的结果为 减少的模数大于最大值可以是由结果代表的 婷型。