如何在GCC中收到有关无符号整数溢出而不是环绕的警告? [英] How to get a warning in GCC for unsigned integer overflow instead of wrap-around?

查看:191
本文介绍了如何在GCC中收到有关无符号整数溢出而不是环绕的警告?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

测试ENV

  • Linux
  • 英特尔x86-64 GCC 8.2.1
  • 已启用标志:-Wextra -Wall -Wfloat-equal -Wundef -Wshadow -Winit-self -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wstrict-overflow=5 -Wwrite-strings -Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion -Wunreachable-code -Wformat=2 -pedantic -pedantic-errors -Werror-implicit-function-declaration -Wformat-security -fstrict-overflow
  • sizeof(long)是8.
  • sizeof(int)是4.
  • Linux
  • Intel x86-64 GCC 8.2.1
  • Flags enabled: -Wextra -Wall -Wfloat-equal -Wundef -Wshadow -Winit-self -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wstrict-overflow=5 -Wwrite-strings -Waggregate-return -Wcast-qual -Wswitch-default -Wswitch-enum -Wconversion -Wunreachable-code -Wformat=2 -pedantic -pedantic-errors -Werror-implicit-function-declaration -Wformat-security -fstrict-overflow
  • sizeof(long) is 8.
  • sizeof(int) is 4.

示例1发出警告,很好:

Example 1, got a warning, good:

long x = 2147483647 * 3;

示例2,没有警告,不好:

Example 2, no warning, not good:

long x = 2147483647U * 3U; // Suffix U

unsigned int a = 2147483647;
unsigned int b = 3;
long x = a*b;

示例3,没有警告,但按预期工作:

Example 3, no warning, but work as expected:

long x = 2147483647L * 3L; // Suffix L

在示例2中,我知道它是环绕式的,而不是整数溢出的,但是这些是编译器无法警告的情况?

根据标准:

否则,将对两个操作数执行整数提升.然后 以下规则适用于提升后的操作数:

Otherwise, the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:

如果两个操作数具有相同的类型,则不需要进一步的转换. 否则,如果两个操作数都具有符号整数类型或都具有无符号整数类型,则将具有较小整数转换等级的操作数转换为具有较高等级的操作数的类型.

If both operands have the same type, then no further conversion is needed. Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.

否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则将带符号整数类型的操作数转换为无符号整数类型的操作数的类型.

Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

否则,如果带符号整数类型的操作数的类型可以表示带无符号整数类型的操作数的所有值,则将带无符号整数类型的操作数转换为带符号整数的操作数的类型类型.

Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, then the operand with unsigned integer type is converted to the type of the operand with signed integer type.

否则,两个操作数都将转换为与带符号整数类型的操作数类型相对应的无符号整数类型.

Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

(6.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.


开始使用带有标志-fsanitize=unsigned-integer-overflow的Clang,该标志可以帮助处理大量不需要的值.那不是整数溢出,但不是预期值.从GCC开始,直到现在还不支持这种警告,请继续使用Clang.


Started using Clang with flag -fsanitize=unsigned-integer-overflow that helps a lot with undesired values from wrap-around. That is not an integer overflow, but not the intended value. Since GCC, until now does not support a warning like this, moving on to Clang.

推荐答案

有符号整数的溢出调用未定义的行为,而无符号整数溢出已得到很好的定义.

Overflow of signed integers invokes undefined behavior, while unsigned integer overflow is well defined.

对于无符号整数,将发生溢出,就好像值是对给定类型的最大值进行模运算后得出的.换句话说,如果类型为n位宽,则仅保留结果的低阶n位.这实际上不是溢出,而是称为环绕.

For unsigned integers, overflow occurs as if the values were computed modulo one more than the maximum value of the given type. Put another way, if the type is n bits wide, then only the low order n bits of the result are retained. This is not actually overflow but is referred to as wraparound.

这在第6.5p9节中详细说明了:

有符号整数的非负值范围
type是相应的无符号整数的子范围 类型,以及每种类型中相同值的表示形式 是一样的涉及无符号操作数的计算可以 永远不会溢出,因为结果无法用 所得的无符号整数类型将以 大于最大值的数字 由结果类型表示.

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. 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.

由于此行为的定义明确,因此编译器触发警告没有意义.

Because this behavior is well defined, it doesn't make sense for the compiler to trigger a warning.

在第二个示例中:

long x = 2147483647U * 3U; 

乘法是在unsigned类型上完成的,因此数学结果6442450941会回绕到2147483645,这在long的范围内.没有溢出(只是环绕),也没有超出范围的转换,因此没有警告.

The multiplication is done on unsigned types, so the mathematical result 6442450941 wraps around to 2147483645, which is within the range of a long. There's no overflow (just wraparound) and no out-of-range conversion, so no warning.

这篇关于如何在GCC中收到有关无符号整数溢出而不是环绕的警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆