【问题标题】:Why is int e = 3000000000 not a warning in gcc?为什么 int e = 3000000000 在 gcc 中不是警告?
【发布时间】: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;

据我所知,从 231232 - 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


【解决方案1】:

根据对问题 cmets 所做的一些调查,我们发现这种行为至少可以追溯到 1993 年 10 月 30 日,Richard Stallman 在this commit 中提供了以下提交消息:

"(convert_and_check): 不要警告将 0xff 转换为有符号字符等,除非迂腐。"

来自-SVN:r5944

似乎作者的意图是在签名char 的机器上将较大的十六进制值卡在chars 中的情况下抑制警告。 (char can be signed or unsigned depending on implementation according to the C standard.)

但这样做,它也适用于任何有符号整数类型的更一般情况,也适用于十进制表示,而不仅仅是十六进制或八进制表示。

在我个人看来,这可能是一个错误功能(我可能只会禁止对十六进制或八进制表示的警告),但这是我认为gcc 维护者比我更有资格做出的判断。

【讨论】:

    猜你喜欢
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 2021-12-27
    • 2017-10-13
    • 2016-03-03
    • 1970-01-01
    • 2022-01-04
    相关资源
    最近更新 更多