【发布时间】:2019-02-23 02:38:38
【问题描述】:
测试环境
- 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。
示例 1,收到警告,很好:
long x = 2147483647 * 3;
示例2,没有警告,不好:
long x = 2147483647U * 3U; // Suffix U
或
unsigned int a = 2147483647;
unsigned int b = 3;
long x = a*b;
示例 3,没有警告,但按预期工作:
long x = 2147483647L * 3L; // Suffix L
在示例 2 中,我知道它是环绕而不是整数溢出,但这些是编译器无法警告的情况?
来自标准:
(6.3.1.8)
否则,整数提升将在两个操作数上执行。然后 以下规则适用于提升的操作数:
如果两个操作数的类型相同,则无需进一步转换。 否则,如果两个操作数都是有符号整数类型或都具有无符号整数类型,则整数转换等级较小的操作数将转换为等级较大的操作数类型。
否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型。
否则,如果有符号整数类型的操作数的类型可以表示无符号整数类型的操作数的所有值,则将无符号整数类型的操作数转换为有符号整数类型的操作数的类型输入。
否则,两个操作数都转换为无符号整数类型,对应有符号整数类型的操作数。
(6.5):
如果在计算表达式期间出现异常情况(即,如果结果未在数学上定义或不在其(类型)的可表示值范围内,则行为未定义。
开始使用带有标志 -fsanitize=unsigned-integer-overflow 的 Clang,这对处理来自环绕的不需要的值有很大帮助。这不是整数溢出,但不是预期值。由于 GCC,直到现在还不支持这样的警告,继续使用 Clang。
【问题讨论】:
-
仅供参考:在 C 标准的术语中,
unsigned整数 never 溢出;他们环绕。 -
在示例二中,您将两个无符号整数相乘,然后将结果回绕,然后该结果将存储在 long 中。
-
值 2147483645 应该是环绕?
标签: c gcc gcc-warning