【发布时间】:2020-06-28 21:56:44
【问题描述】:
考虑以下 C 程序:
#include <stdio.h>
int main(int argc, char *argv[]) {
int a = -5000000000;
int b = -3000000000;
int c = -1000000000;
int d = 1000000000;
int e = 3000000000;
int f = 5000000000;
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
printf("d = %d\n", d);
printf("e = %d\n", e);
printf("f = %d\n", f);
return 0;
}
考虑一下这个环境输出:
pvz@DESKTOP-OTTHA70:~$ uname -a
Linux DESKTOP-OTTHA70 4.19.104-microsoft-standard #1 SMP Wed Feb 19 06:37:35 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
pvz@DESKTOP-OTTHA70:~$ gcc --version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
这个编译器输出:
pvz@DESKTOP-OTTHA70:~$ gcc -Wall -o overflow overflow.c
overflow.c: In function ‘main’:
overflow.c:4:10: warning: overflow in implicit constant conversion [-Woverflow]
int a = -5000000000;
^
overflow.c:5:10: warning: overflow in implicit constant conversion [-Woverflow]
int b = -3000000000;
^
overflow.c:9:11: warning: overflow in implicit constant conversion [-Woverflow]
int f = 5000000000;
^~~~~~~~~~
这个程序输出:
pvz@DESKTOP-OTTHA70:~$ ./overflow
a = -705032704
b = 1294967296
c = -1000000000
d = 1000000000
e = -1294967296
f = 705032704
在这台机器上,一个 int 是 32 位宽的,它的范围是 -231 (-2147483648) 到 231 - 1 (2147483647) 包括在内。
正如预期的那样,尝试将一个不适合该范围的值放入变量中会导致警告,并且该值的最高有效位被截断,从而导致整数变量 a、b、e 中出现意外值和f。
但是,编译器只警告我们 a、b 和 f,而不是 e。
因此问题是,为什么 gcc 不警告以下行?
int e = 3000000000;
据我所知,从 231 到 232 - 1 的值令人惊讶地足够了如果您尝试将它们塞进 int 中,实际上不会发出警告。我也怀疑这是一个编译器错误,因为这似乎是很长时间以来就会发现的东西。这意味着它可能是故意行为。但为什么呢?
【问题讨论】:
-
使用
-Wall -Wextra -pedantic-errors,gcc 警告所有人:godbolt.org/z/n-FLKk -
在为二进制补码平台设计的代码中,故意编写一个环绕并变为负数的正值并不少见,例如
int mask = 0xffff0000。 gcc 开发人员可能认为对此类情况发出警告会产生太多误报。 -
好的,查看源代码。伙计,他们有一个奇怪的缩进约定。 This 是打印溢出警告的函数。我什至不会试图解释它。我喜欢的宏太多而代码文档太少^^
-
@Teharez 我在挖掘方面取得了一些进展,而且似乎只有 Richard Stallman 早在 1993 年就做出了这个提交。背后没有任何理由,因为提交似乎很常见当时的消息。不确定这是否让我们更接近。 github.com/gcc-mirror/gcc/commit/…
-
@PervonZweigbergk:提交评论提到
char是一个很好的提示,因为这种情况在char中可能比int更常见。一方面,存在char在某些实现中已签名而在其他实现中未签名的问题。但大多数程序员倾向于认为0x7f以上的字符值是正数而不是负数,所以char c = 0xff;确实很常见。
标签: c gcc integer integer-overflow