C编译器为什么很难获得-Wwrite-strings警告?

问题描述 投票:2回答:2

考虑此C代码:

void foo(char *);

void bar(void) {
    foo("");
}

[当我使用带有GCC或Clang的-pedantic -Wall -Wextra或带有Clang的-Weverything进行编译时,它在没有给出任何相关警告的情况下进行编译。如果我添加-Wwrite-strings,那么GCC会给我这个信息:

<source>:4:9: warning: passing argument 1 of 'foo' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    4 |     foo("");
      |         ^~
<source>:1:10: note: expected 'char *' but argument is of type 'const char *'
    1 | void foo(char *);
      |          ^~~~~~

叮当给了我这个:

<source>:4:9: warning: passing 'const char [1]' to parameter of type 'char *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
    foo("");
        ^~
<source>:1:16: note: passing argument to parameter here
void foo(char *);
               ^

在我看来很多事情都不对:

  • 这似乎是一个非常重要的警告,不仅默认情况下处于关闭状态,而且即使人们实践中采用了大多数方式来使警告处于关闭状态,也要处于关闭状态。
  • [GCC的输出引用了-Wdiscarded-qualifiers,但是如果我通过它而不是-Wwrite-strings,则不会收到该警告。
  • 我以为-Weverything的意思是“实际上编译器知道的每一个警告”,但这似乎与此矛盾。
  • 如果我编译与C ++而不是C相同的代码,则GCC和Clang都向我发出我想要的警告,而根本不需要任何编译器标志。我不确定为什么这里的语言之间会有区别,因为AFAIK,如果您实际写入字符串文字,那么C和C ++都有未定义的行为。

这里发生了什么?为什么此特定警告似乎如此错误?

c gcc clang compiler-warnings gcc-warning
2个回答
2
投票

在C中,字符串文字在const之前存在。因此C字符串文字不是const限定的(尽管尝试写入它们的结果未由C标准定义)。如果将字符串文字设为const限定,则许多旧版软件会因类型错误而损坏。 C委员会认为此更改不值得。

尽管-Wwrite-strings,但开关-W并不是真正的警告开关。它将正在编译的语言更改为非标准C,其中字符串文字是const限定的。这解释了为什么在将字符串文字分配给-Wdiscarded-qualifier时GCC会显示char *,并且还解释了为什么单独-Wdiscarded-qualifier不会触发这些警告的原因-因为没有-Wwrite-strings,所以字符串文字不是const限定的,因此该分配不会丢弃任何限定词。

大概是Clang的-Weverything不包含-Wwrite-strings,因为如上所述,它并不是真正的警告选项,并且因为它将语言更改为非标准C。


1
投票

这似乎是一个非常重要的警告,不仅默认情况下处于关闭状态,而且即使人们实践中采用了大多数方式来使警告处于关闭状态,也要处于关闭状态。

嗯,gcc的作者不同意您的意见,他们在手册中解释了原因:

-Wwrite-strings

[编译C时,将字符串常量的类型设置为const char[length],以便将一个地址复制到非const char *指针中会产生警告。这些警告可以帮助您在编译时找到可以尝试写入字符串常量的代码,但前提是您非常注意在声明和原型中使用const。否则,这只是个麻烦。这就是为什么我们没有使-Wall请求这些警告的原因。

这也解释了您的第二个问题:

[GCC的输出引用-Wdiscarded-qualifiers,但是如果我通过它而不是-Wwrite-strings,则不会收到该警告。

由于没有-Wwrite-strings,字符串常量仅具有类型char[],因此没有任何限定符被丢弃。

(这也解释了为什么消息中提到-Wdiscarded-qualifiers而不是-Wwrite-strings;问题确实是丢弃的限定词,并且该警告代码没有回溯告诉您,唯一的原因是第一名是因为有一个不同的选择。那将非常复杂。)

我以为-万物的意思是“实际上编译器知道的每一个警告”,但这似乎与此矛盾。

是的,这就是clang手册声称的意思:

除了传统的-W标志,还可以通过传递-Weverything来启用所有诊断。这与-Werror一起正常工作,并且还包含-pedantic的警告。

确实,这已被记录为错误:https://bugs.llvm.org/show_bug.cgi?id=18801。显然-Weverything确实在clang 3.4及更早版本中启用了此警告,但存在回归(或未记录的有意更改)。

© www.soinside.com 2019 - 2024. All rights reserved.