比较无符号与有符号不会发出警告(使用 const)

comparing unsigned vs signed does not make a warning (using const)

简单:如果我在 GCC 中测试有符号变量与无符号变量,编译时 -Wall 我会收到警告。

使用此代码:

#include <stdio.h>

int main(int argc, char* argv[])
{
    /* const */ unsigned int i = 0;
    if (i != argc)
        return 1;
    return 0;
}

我收到此警告:

<source>: In function 'int main(int, char**)':
<source>:6:8: warning: comparison of integer expressions of different signedness: 'unsigned int' and 'int' [-Wsign-compare]
    6 |  if (i != argc)
      |      ~~^~~~~~~
Compiler returned: 0

但是,如果我取消注释 const - 编译器会很高兴。我几乎可以在每个 GCC 版本上重现它(参见 https://godbolt.org/z/b6eoc1)。这是 GCC 中的错误吗?

只需使用 -Wall -Wextra,您就会收到警告。

我建议使用 -Wall -Wextra -pedantic 编译器选项

https://godbolt.org/z/TvqeKn

编辑

作为对非常不友好和不友好的 OP 评论的澄清。 -Wextra 启用以下警告包括 OP 想要的警告

warning: comparison of integer expressions of different signedness:
 'unsigned int' and 'int' [-Wsign-compare]
    9 |     if (i != argc)

我认为您缺少的是编译器优化。如果没有 const,该变量就是一个变量,这意味着它可以更改。既然是unsigned int,说明确实可以大于整数。

const unsigned int i = 2147483648;

如果您将大于 int 的最大值的值分配给该无符号整数,您将恢复错误。

但是如果是const,编译器知道它的值,它知道,不会改变,比较不会有问题。

如果你看一下程序集,你会发现没有const,它实际上是取变量的值来比较:

movl    [=11=], -4(%rbp)
movl    -20(%rbp), %eax
cmpl    %eax, -4(%rbp)

现在,如果它是 const,它根本不会理会变量,它只取值:

movl    [=12=], -4(%rbp)
cmpl    [=12=], -20(%rbp)

我会说这是 -Wsign-compare 选项中的编译器错误。

通过使用 -Wall -Wextra -O3 编译您的示例进行测试。添加 -O3 后,警告在 const 情况下突然消失。即使生成的带有或不带有 const 的机器代码是相同的。这没有任何意义。

当然,const 和生成的机器代码都不会影响 C 操作数的符号性,因此根据类型限定符或优化器设置,警告不应该不一致。

问题标记为 C,但链接到 C++ Godbolt 示例。这是警告发出时显示的 table:1

C non-const C const C++ non-const C++ const
Default warnings No No No No
-Wall No No Yes No
-Wall -Wextra Yes Yes Yes No

因此,在 C 中,GCC 在 -Wextra 中提供警告,而不考虑 const 资格。

在 C++ 中,GCC 在 -Wall 中提供警告,但将 const 合格对象视为可以抑制警告的已知值。

GCC documentation 表示,对于 -Wsign-compare:

Warn when a comparison between signed and unsigned values could produce an incorrect result when the signed value is converted to unsigned. In C++, this warning is also enabled by -Wall. In C, it is also enabled by -Wextra.

请注意,它并没有说它会在有符号值和无符号值之间进行比较时发出警告,而是在这种比较可能产生错误结果时发出警告。因此,当对象的定义使得比较不能产生不正确的结果时不提供警告不是错误。

“可以”一词为编译器“了解”对象的内容留有余地。未能确定 C const 情况不能产生不正确的结果可以描述为错误,尽管将其描述为缺点可能更好。

脚注

1 table 中的“Const”专门使用了一个对象,该对象是 const 限定的,其值可通过可见定义立即供编译器使用.我没有测试这样的情况,例如,为一个 const 限定的对象声明了一个标识符,但它的定义在另一个翻译单元中。