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

时间:2021-03-01 21:26:23

Edited to include proper standard reference thanks to Carl Norum.

感谢Carl Norum的编辑,包括适当的标准参考。

The C standard states

C标准状态

If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

如果在表达式的评估过程中出现异常情况(也就是说,如果结果没有在数学上定义或不在其类型的可表示值范围内),则该行为是未定义的。

Are there compiler switches that guarantee certain behaviors on integer overflow? I'd like to avoid nasal demons. In particular, I'd like to force the compiler to wrap on overflow.

是否有编译器开关来保证整数溢出的某些行为?我想避开鼻魔。特别是,我想强制编译器对溢出进行包装。

For the sake of uniqueness, let's take the standard to be C99 and the compiler to be gcc. But I would be interested in answers for other compilers (icc, cl) and other standards (C1x, C89). In fact, just to annoy the C/C++ crowd, I'd even appreciate answers for C++0x, C++03, and C++98.

为了惟一性,我们将标准设为C99,编译器设为gcc。但是我对其他编译器(icc, cl)和其他标准(C1x, C89)的答案感兴趣。事实上,为了让C/ c++人群感到厌烦,我甚至想知道c++ 0x、c++ 03和c++ 98的答案。

Note: International standard ISO/IEC 10967-1 may be relevant here, but as far as I could tell it was mentioned only in the informative annex.

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

6 个解决方案

#1


21  

Take a look at -ftrapv and -fwrapv:

看看-ftrapv和-fwrapv:

-ftrapv

-ftrapv

This option generates traps for signed overflow on addition, subtraction, multiplication operations.

此选项为加、减、乘操作上的带符号溢出生成陷阱。

-fwrapv

-fwrapv

This option instructs the compiler to assume that signed arithmetic overflow of addition, subtraction and multiplication wraps around using twos-complement representation. This flag enables some optimizations and disables other. This option is enabled by default for the Java front-end, as required by the Java language specification.

这个选项指示编译器假设有符号的算术溢出、减法和乘法将使用两个s-补体表示。此标志允许进行一些优化,并禁用其他的。根据Java语言规范的要求,Java前端默认启用此选项。

#2


13  

For your C99 answer, I think 6.5 Expressions, paragraph 5 is what you're looking for:

对于C99的回答,我认为是6.5个表达,第5段就是你要找的:

If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

如果在表达式的评估过程中出现异常情况(也就是说,如果结果没有在数学上定义或不在其类型的可表示值范围内),则该行为是未定义的。

That means if you get an overflow, you're out of luck - no behaviour of any kind guaranteed. Unsigned types are a special case, and never overflow (6.2.5 Types, paragraph 9):

这就意味着,如果你出现溢流现象,那你就不走运了——任何行为都不能得到保证。无符号类型是一种特殊情况,从不溢出(6.2.5类型,第9段):

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

涉及无符号操作数的计算永远不会溢出,因为结果不能由结果的无符号整数类型表示的结果会根据结果类型可以表示的大于最大值的数量而减少。

C++ has the same statements, worded a bit differently:

c++也有同样的表述,只是措辞有点不同:

  • 5 Expressions, paragraph 4:

    5表情,第四段:

    If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined. [Note: most existing implementations of C++ ignore integer overflows. Treatment of division by zero, forming a remainder using a zero divisor, and all floating point exceptions vary among machines, and is usually adjustable by a library function. —endnote]

    如果在计算表达式的过程中,结果在数学上没有定义,或者在其类型的可表示值范围内没有定义,则行为是未定义的。[注意:大多数c++的现有实现忽略了整数溢出。通过零除来处理除法,使用零除来形成余数,所有浮点异常在不同的机器中都是不同的,并且通常可以通过库函数来调节。尾注)

  • 3.9.1 Fundamental types, paragraph 4:

    3.9.1基本类型,第4段:

    Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2^n where n is the number of bits in the value representation of that particular size of integer.

    无符号整数,宣布无符号,应当遵守法律的算术模2 ^ n,n的值的比特数表示特定大小的整数。

#3


7  

In C99 the general behavior is desribed in 6.5/5

在C99中,一般行为在6.5/5中被描述

If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

如果在表达式的评估过程中出现异常情况(也就是说,如果结果没有在数学上定义或不在其类型的可表示值范围内),则该行为是未定义的。

The behavior of unsigned types is described in 6.2.5/9, which basically states that operations on unsigned types never lead to exceptional condition

无符号类型的行为在6.2.5/9中进行了描述,它基本上说明了对无符号类型的操作不会导致异常情况

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

涉及无符号操作数的计算永远不会溢出,因为结果不能由结果的无符号整数类型表示的结果会根据结果类型可以表示的大于最大值的数量而减少。

GCC compiler has a special option -ftrapv, which is intended to catch run-time overflow of signed integer operations.

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

#4


4  

For completeness, I'd like to add that Clang now has "checked arithmetic builtins" as a language extension. Here is an example using checked unsigned multiplication:

为了完整起见,我想补充一点,Clang现在已经将“检查算术内置项”作为语言扩展。这里有一个使用检查无符号乘法的例子:

unsigned x, y, result;
...
if (__builtin_umul_overflow(x, y, &result)) {
    /* overflow occured */
    ...
}
...

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

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

#5


2  

6.2.5 paragraph 9 is what you're looking for:

6.2.5第9段是你要找的:

The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type, and the representation of the same value in each type is the same.31) A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

负的有符号整数类型的值的范围是一个附属的区域相应的无符号整数类型,和相同的值在每个类型的表示法是same.31)涉及无符号计算操作数不能溢出,因为结果不能代表产生的无符号整数类型模数量减少是一个大于最大的值可以由生成的类型。

#6


0  

I'm not sure if there are any compiler switches you can use to enforce uniform behavior for overflows in C/C++. Another option is to use the SafeInt<T> template. It's a cross platform C++ template that provides definitive overflow / underflow checks for all types of integer operations.

我不确定是否可以使用任何编译器开关来为c++中的溢出强制执行统一的行为。另一个选项是使用SafeInt 模板。它是一个跨平台的c++模板,为所有类型的整数操作提供确定的溢出/欠流检查。

#1


21  

Take a look at -ftrapv and -fwrapv:

看看-ftrapv和-fwrapv:

-ftrapv

-ftrapv

This option generates traps for signed overflow on addition, subtraction, multiplication operations.

此选项为加、减、乘操作上的带符号溢出生成陷阱。

-fwrapv

-fwrapv

This option instructs the compiler to assume that signed arithmetic overflow of addition, subtraction and multiplication wraps around using twos-complement representation. This flag enables some optimizations and disables other. This option is enabled by default for the Java front-end, as required by the Java language specification.

这个选项指示编译器假设有符号的算术溢出、减法和乘法将使用两个s-补体表示。此标志允许进行一些优化,并禁用其他的。根据Java语言规范的要求,Java前端默认启用此选项。

#2


13  

For your C99 answer, I think 6.5 Expressions, paragraph 5 is what you're looking for:

对于C99的回答,我认为是6.5个表达,第5段就是你要找的:

If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

如果在表达式的评估过程中出现异常情况(也就是说,如果结果没有在数学上定义或不在其类型的可表示值范围内),则该行为是未定义的。

That means if you get an overflow, you're out of luck - no behaviour of any kind guaranteed. Unsigned types are a special case, and never overflow (6.2.5 Types, paragraph 9):

这就意味着,如果你出现溢流现象,那你就不走运了——任何行为都不能得到保证。无符号类型是一种特殊情况,从不溢出(6.2.5类型,第9段):

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

涉及无符号操作数的计算永远不会溢出,因为结果不能由结果的无符号整数类型表示的结果会根据结果类型可以表示的大于最大值的数量而减少。

C++ has the same statements, worded a bit differently:

c++也有同样的表述,只是措辞有点不同:

  • 5 Expressions, paragraph 4:

    5表情,第四段:

    If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined. [Note: most existing implementations of C++ ignore integer overflows. Treatment of division by zero, forming a remainder using a zero divisor, and all floating point exceptions vary among machines, and is usually adjustable by a library function. —endnote]

    如果在计算表达式的过程中,结果在数学上没有定义,或者在其类型的可表示值范围内没有定义,则行为是未定义的。[注意:大多数c++的现有实现忽略了整数溢出。通过零除来处理除法,使用零除来形成余数,所有浮点异常在不同的机器中都是不同的,并且通常可以通过库函数来调节。尾注)

  • 3.9.1 Fundamental types, paragraph 4:

    3.9.1基本类型,第4段:

    Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2^n where n is the number of bits in the value representation of that particular size of integer.

    无符号整数,宣布无符号,应当遵守法律的算术模2 ^ n,n的值的比特数表示特定大小的整数。

#3


7  

In C99 the general behavior is desribed in 6.5/5

在C99中,一般行为在6.5/5中被描述

If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

如果在表达式的评估过程中出现异常情况(也就是说,如果结果没有在数学上定义或不在其类型的可表示值范围内),则该行为是未定义的。

The behavior of unsigned types is described in 6.2.5/9, which basically states that operations on unsigned types never lead to exceptional condition

无符号类型的行为在6.2.5/9中进行了描述,它基本上说明了对无符号类型的操作不会导致异常情况

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

涉及无符号操作数的计算永远不会溢出,因为结果不能由结果的无符号整数类型表示的结果会根据结果类型可以表示的大于最大值的数量而减少。

GCC compiler has a special option -ftrapv, which is intended to catch run-time overflow of signed integer operations.

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

#4


4  

For completeness, I'd like to add that Clang now has "checked arithmetic builtins" as a language extension. Here is an example using checked unsigned multiplication:

为了完整起见,我想补充一点,Clang现在已经将“检查算术内置项”作为语言扩展。这里有一个使用检查无符号乘法的例子:

unsigned x, y, result;
...
if (__builtin_umul_overflow(x, y, &result)) {
    /* overflow occured */
    ...
}
...

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

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

#5


2  

6.2.5 paragraph 9 is what you're looking for:

6.2.5第9段是你要找的:

The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type, and the representation of the same value in each type is the same.31) A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

负的有符号整数类型的值的范围是一个附属的区域相应的无符号整数类型,和相同的值在每个类型的表示法是same.31)涉及无符号计算操作数不能溢出,因为结果不能代表产生的无符号整数类型模数量减少是一个大于最大的值可以由生成的类型。

#6


0  

I'm not sure if there are any compiler switches you can use to enforce uniform behavior for overflows in C/C++. Another option is to use the SafeInt<T> template. It's a cross platform C++ template that provides definitive overflow / underflow checks for all types of integer operations.

我不确定是否可以使用任何编译器开关来为c++中的溢出强制执行统一的行为。另一个选项是使用SafeInt 模板。它是一个跨平台的c++模板,为所有类型的整数操作提供确定的溢出/欠流检查。