“ stderr;”声明不会发出警告

时间:2020-05-31 20:27:41

标签: c gcc stdout stderr gcc-warning

假设我有这样的源代码:

#include <stdio.h>

FILE *p;

int main(void) {
    p;
}

...,它将编译(使用gcc)而没有任何错误或警告-除非我打开-Wall,否则将输出statement with no effect警告。

但是代码是否像这样:

#include <stdio.h>

int main(void) {
    stderr;
}

...不论-Wall,都不会显示警告。

我在这里想念东西吗?

gcc版本9.3.0

2 个答案:

答案 0 :(得分:2)

该程序:

$ cat main.c
#include <stdio.h>

int main(void)
{
    FILE *p;
    42;         // statement with no effect
    p;          // statement with no effect
    stderr;     // statement with no effect
    return 0;
}

可能会引发3 statement with no effect 引发任何问题时进行诊断。但是,正如您所发现的, 在gcc手中,那是不正确的。

$ gcc --version
gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0
...

$ gcc -Wall -c main.c
main.c: In function ‘main’:
main.c:6:5: warning: statement with no effect [-Wunused-value]
    6 |     42;
      |     ^~
main.c:7:5: warning: statement with no effect [-Wunused-value]
    7 |     p;
      |     ^

stderr-表示FILE *,就像p一样-可以免费通过 评估无效。

众所周知,-Wall不能真的启用所有警告。但是这个免费 通行证可幸存至诊断严谨的常规极限:

$ gcc -Wall -Wextra -pedantic -c main.c
main.c: In function ‘main’:
main.c:6:5: warning: statement with no effect [-Wunused-value]
    6 |     42;
      |     ^~
main.c:7:5: warning: statement with no effect [-Wunused-value]
    7 |     p;
      |     ^

我们应该清楚,此免费通行证是由 identfier 携带的 stderr,与它命名的值不同:-

通过将另一个等于FILE *不能将其转移到另一个stderr

$ cat main.c; gcc -Wall -c main.c
#include <stdio.h>

int main(void)
{
    FILE *p = stderr;
    42;
    p;
    return 0;
}

main.c: In function ‘main’:
main.c:6:5: warning: statement with no effect [-Wunused-value]
    6 |     42;
      |     ^~
main.c:7:5: warning: statement with no effect [-Wunused-value]
    7 |     p;
      |     ^

如果我们不将其称为FILE *,那么stderr并不真正地 stderr

$ cat main.c; gcc -Wall -c main.c
#include <stdio.h>

int main(void)
{
    FILE **p = &stderr;
    42;
    *p;     // a.k.a `stderr`
    return 0;
}

main.c: In function ‘main’:
main.c:6:5: warning: statement with no effect [-Wunused-value]
    6 |     42;
      |     ^~
main.c:7:5: warning: statement with no effect [-Wunused-value]
    7 |     *p;     // a.k.a `stderr`
      |     ^~

但是另一方面,即使将stderr 称为stderr, 如果该识别码小于等于,则免费通行证被没收 评估的整个上下文无效:

$ cat main.c; gcc -Wall -c main.c
#include <stdio.h>

int main(void)
{
    stdout;             // Undiagnosed
    stderr;             // Undiagnosed
    stderr, stdout;     // Diagnosed once
    42, stderr;         // Diagnosed twice
    stderr - stdout;    // Diagnosed once
    (stderr);           // Diagnosed once
    return 0;
}

main.c: In function ‘main’:
main.c:7:11: warning: left-hand operand of comma expression has no effect [-Wunused-value]
    7 |     stderr, stdout;     // Diagnosed once
      |           ^
main.c:8:7: warning: left-hand operand of comma expression has no effect [-Wunused-value]
    8 |     42, stderr;         // Diagnosed twice
      |       ^
main.c:8:5: warning: statement with no effect [-Wunused-value]
    8 |     42, stderr;         // Diagnosed twice
      |     ^~
main.c:9:12: warning: statement with no effect [-Wunused-value]
    9 |     stderr - stdout;    // Diagnosed once
      |            ^
main.c:10:5: warning: statement with no effect [-Wunused-value]
   10 |     (stderr);           // Diagnosed once
      |     ^

在这里,我假设stderr的情况也是如此 为stdout辩护。值得注意的是,42, stderr; 被诊断为无效语句,stderr, stdout;无效。

可以公平地说,gcc并不像对自然和 想要扩展到stderr的诊断免疫的限制 合格标识符。当我们探究 除了与编译器隔离之外,没有人编写的代码种类繁多。

尽管如此,人们还是想弄清楚这种诊断的动机 豁免权,并知道是否可以告知gcc撤销其豁免权,例如所有的 我在程序中编写的无效语句将被诊断为这样。

第二个分数的答案是:

$ cat main.c; gcc -Wall -Wsystem-headers -c main.c
#include <stdio.h>

int main(void)
{
    FILE *p;
    42;         // statement with no effect
    p;          // statement with no effect
    stderr;     // statement with no effect
    return 0;
}
main.c: In function ‘main’:
main.c:6:5: warning: statement with no effect [-Wunused-value]
    6 |     42;         // statement with no effect
      |     ^~
main.c:7:5: warning: statement with no effect [-Wunused-value]
    7 |     p;          // statement with no effect
      |     ^
In file included from main.c:1:
main.c:8:5: warning: statement with no effect [-Wunused-value]
    8 |     stderr;     // statement with no effect
      |     ^~~~~~

和:

$ cat main.c; gcc -Wall -Wsystem-headers -c main.c
#include <stdio.h>

int main(void)
{
    stdout;
    stderr;
    stderr, stdout;
    42, stderr;
    stderr - stdout;
    (stderr);
    return 0;
}
In file included from main.c:1:
main.c: In function ‘main’:
main.c:5:5: warning: statement with no effect [-Wunused-value]
    5 |     stdout;
      |     ^~~~~~
main.c:6:5: warning: statement with no effect [-Wunused-value]
    6 |     stderr;
      |     ^~~~~~
main.c:7:11: warning: left-hand operand of comma expression has no effect [-Wunused-value]
    7 |     stderr, stdout;
      |           ^
In file included from main.c:1:
main.c:7:5: warning: statement with no effect [-Wunused-value]
    7 |     stderr, stdout;
      |     ^~~~~~
main.c:8:7: warning: left-hand operand of comma expression has no effect [-Wunused-value]
    8 |     42, stderr;
      |       ^
main.c:8:5: warning: statement with no effect [-Wunused-value]
    8 |     42, stderr;
      |     ^~
main.c:9:12: warning: statement with no effect [-Wunused-value]
    9 |     stderr - stdout;
      |            ^
main.c:10:5: warning: statement with no effect [-Wunused-value]
   10 |     (stderr);
      |     ^

还有documentation of -Wsystem-headers 提供了激励性的理由:

-Wsystem标题

为在系统头文件中找到的结构打印警告消息。来自的警告 通常假设系统标头通常不抑制系统标头 表示真正的问题,只会使编译器的输出难以阅读。 使用此命令行选项告诉GCC从系统标头发出警告,如下所示: 如果它们出现在用户代码中。 ...

因此,stderrstderr通过在系统中声明而获得诊断豁免 标头<stdio.h> 1 。默认情况下,系统标题中的警告被假定为 虚伪。

但是,在开展业务之前,值得一提的是,对 -Wsystem-headers的影响以及它的缺失实际上并不能解释 我们观察到的那些效果。诊断失败

stderr;     // statement with no effect
在没有-Wsystem-headers的情况下,第一个程序中的

not 来自系统标题的警告。它是禁止来自main.c的警告, 该语句与以下语句完全一样无效:

p;          // statement with no effect

-Wsystem-headers对程序编译的影响不大 GCC开始从系统标头中发出任何先前禁止的警告 好像发生在用户代码中一样。这会导致GCC发出先前被抑制的 一直在用户代码中发生警告。

显然,默认-Wno-system-headers的实际效果至少包括 在上下文中禁止显示某些警告(无论是否使用用户代码)

... identifier ...
否则会引起警告的

包含已声明的identifier 在系统标题中。手册告诉我们如何停止此操作,但仅手势 在解释它。


[1]在文档中,系统头的含义并不明显, 但实验表明,文件只是该文件中的系统头文件 如果它是GCC安装的头文件,则具有适当的意义。

答案 1 :(得分:-1)

是的...并且如果您编写类似的内容:

0;

#include <math.h>
int main()
{

    cos(2.0*M_PI + 7.0);
}

您将得到相同的结果(什么都不会发生)。原因是语句可以是任何表达式(任何类型),后跟C中的分号;。表达式值刚刚删除,执行继续执行下一条语句(在您的情况下没有)。在我的示例中,编译器只是删除了表达式的0值或字符串文字"Hello world",结果为空。