使用-pedantic选项在GCC/G++编译器中的目的是什么?

176

这篇文章 表示:

-ansi:告诉编译器实现 ANSI 语言选项,关闭某些 GCC 不符合 ANSI 标准的“特性”。

-pedantic:与 -ansi 同时使用,严格遵守 ANSI 标准,拒绝任何不符合标准的代码。

首先明确:

  • -pedantic-ansi 选项是GCC/G++编译器的作用?(我没看懂上述描述)
  • 在哪些情况下应该使用这两个选项?
  • 什么时候需要使用它们?
  • 它们重要吗?
回答: - -pedantic-ansi 是GCC/G++编译器的选项,用来控制是否严格遵守C/C++语言的标准规范。 - 在编写跨平台代码时,为了避免不同编译器实现的差异,可以考虑使用这两个选项。 - 在需要最大程度地控制代码规范、确保代码可移植性的情况下,应该使用这两个选项。 - 它们非常重要,能够帮助开发者在编写代码时尽可能地符合C/C++标准,从而提高代码质量和可维护性。

2
太酷了,C编译器甚至不遵循特定语言的标准规范(顺便说一下,这些规范要花费数百美元才能被允许阅读),即使你明确告诉它们,除非你告诉它们“不,实际上认真遵守我告诉你要遵守的标准”。好的用户界面设计! - iono
8个回答

135

我在编码中经常使用它。

-ansi标志等同于-std=c89。如前所述,它关闭了GCC的一些扩展功能。添加-pedantic会关闭更多的扩展功能并生成更多警告。

  • 例如,如果你有一个字符串字面量超过509个字符,那么-pedantic会发出警告,因为它超过了C89标准所要求的最小限制。也就是说,每个C89编译器必须接受长度为509的字符串;它们可以接受更长的字符串,但如果你要严格遵守规范,使用更长的字符串是不可移植的,即使编译器允许接受更长的字符串,而且没有启用严格警告,GCC也会接受它们。

5
@huahsin68: 大致上是这样。MSVC是一种与大多数其他编译器不同的编译器,更适应其特定的生态系统,并且在其生态系统之外不可用。它以自己的方式做很多事情,这与标准不同。然而,如果你使用标准头文件等内容,那么MSVC和GCC相对相似。但是,使用“-std=c89 -pedantic”可以使你更轻松地在其他平台上切换不同的编译器。一旦你开始使用< windows.h >,就会导致与其他系统的兼容性问题。 - Jonathan Leffler
3
因为像其他供应商一样(虽然GNU不以现金销售其编译器),他们希望您使用他们的专有功能?或者更一般地说,因为他们认为这些扩展很有用,并认为它们应该默认启用。 - Jonathan Leffler
2
不管怎样,我已经基本停止使用“-pedantic”了,但是当我重新启用它时,我的大部分代码仍然可以正常编译(唯一一个没有成功的程序明确地使用了“__int128”类型,这是严格来说不正确的)。我认为在GCC太吵闹(对我来说)的时候,有一个干扰阶段。我刚刚测试了大约300个源文件——一些库代码,一些命令,一些SO测试程序——只有一个预期的问题。目前在Mac OS X 10.9.2上使用GCC 4.8.2。 - Jonathan Leffler
1
@JonathanLeffler,是的,我正在查询实际上哪个编译器的名称无法正常工作?是否有这样的编译器? - Pacerier
1
请注意,gcc的发布早于C语言标准,我怀疑作者希望标准能够包含一些被排除在C89之外的gcc特性。-pedantic标志基本上用于标记gcc作者认为优秀编译器应该支持的内容。gcc作者对标准的态度与现今维护者的态度非常不同。 - supercat
显示剩余8条评论

114

GCC编译器总是尝试编译您的程序,如果可能的话。然而,在某些情况下,C和C ++标准规定某些扩展是被禁止的。像GCC或g ++这样符合标准的编译器在遇到这些扩展时必须发出诊断。

例如,GCC编译器的-pedantic选项会导致GCC在这种情况下发出警告。使用更严格的-pedantic-errors选项将这样的诊断警告转换为错误,这将导致编译在这些点上失败。只有那些需要由符合标准的编译器标记的非ISO构造才会生成警告或错误。


3
ISO C和C++标准只是“禁止扩展”,即扩展不能改变符合规范的程序的行为。编译器不必拒绝使用扩展的任何程序。 - M.M
@M.M:需要注意的是,当一些编译器可以接受一个有用的结构而其他编译器会拒绝它时,委员会的“妥协”是要求符合规范的实现必须发出诊断,程序员可以忽略它,从而避免委员会强制或禁止该结构的需要。 - supercat
1
请注意,-pedantic-errors 不等同于 -Werror=pedantic,它们执行不同的检查。 - Warp

39

-ansi 是一个过时的开关,请求编译器按照30年前的过时的C标准修订版 ISO/IEC 9899:1990 进行编译,这本质上是ANSI标准 X3.159-1989 "Programming Language C" 的重新命名。为什么过时?因为在ISO发布了C90之后,ISO一直负责C标准化,并且对C90的任何技术勘误都已经被ISO标准化。因此,更适合使用-std=c90

没有这个开关,最近的GCC C编译器将符合ISO/IEC 9899:2011或最新的2018修订版中规定的C语言标准。

不幸的是,有些懒惰的编译器供应商认为坚持使用旧的过时标准修订版是可以接受的,而这些标准化文档甚至无法从标准机构获取。

使用该开关有助于确保代码可以在这些过时的编译器中进行编译。


-pedantic 是一个有趣的选项。如果没有 -pedantic,即使请求了特定的标准,GCC 仍将允许一些不符合 C 标准的扩展。例如考虑下面的程序:

struct test {
    int zero_size_array[0];
};

C11草案n1570第6.7.6.2p1节中提到:

除了可选的类型限定符和关键字static之外,[和]可以用来界定一个表达式或*。如果它们界定了一个表达式(指定数组的大小),那么该表达式必须具有整数类型。如果该表达式是一个常量表达式,它的值必须大于零。[...]

C标准要求数组的长度必须大于零;而这段话属于约束条件;标准在5.1.1.3p1节中如下所述:

即使行为也明确规定为未定义或实现定义,符合规范的实现应当以一种实现定义的方式产生至少一条诊断消息,如果预处理翻译单元或翻译单元包含任何语法规则或约束条件的违反。在其他情况下,不需要产生诊断消息。9)

然而,如果您使用gcc -c -std=c90 pedantic_test.c编译程序,则不会产生警告。

-pedantic使编译器实际上遵守C标准;因此现在它将生成诊断消息,正如标准所要求的那样:

gcc -c -pedantic -std=c90 pedantic_test.c
pedantic_test.c:2:9: warning: ISO C forbids zero-size array ‘zero_size_array’ [-Wpedantic]
     int zero_size_array[0];
         ^~~~~~~~~~~~~~~

因此,为了实现最大的可移植性,仅仅指定标准修订版是不够的,您还必须使用-pedantic(或-pedantic-errors)来确保GCC实际上符合标准的要求。


这个问题的最后一部分是关于在C++中使用-ansi。 ANSI从未标准化C++语言 - 只是从ISO中采用了它,因此这就像说“由法国标准化的英语”一样没有意义。然而,GCC似乎仍然接受它来编译C++,尽管听起来很愚蠢。

5
请注意语言标准已有进一步修订。今天我通常使用"-std=c11 -Wall -Wextra -Wpedantic -Wconversion"进行编译。 - Davislor
1
我还要补充一点,你应该始终明确指定标准。例如:-std=c++20 - user4945014
实际上,官方文档中写道:“在 C 模式下,这个选项(即:-ansi)等同于 -std=c90。” - Lover of Structure
@LoverofStructure 是的,这就是为什么我喜欢明确地说“-std=c90”,这样你就不用猜测它到底意味着什么 :D - Antti Haapala -- Слава Україні

15

基本上,这将使您的代码更容易在其他实现 ANSI 标准的编译器下编译,并且如果您在使用库/ API 调用方面非常小心,还可以在其他操作系统/平台下编译。

第一个选项关闭了 GCC 的特定功能(-ansi)。

第二个选项将对任何不符合标准的内容发出警告(不仅包括 GCC 的特定功能,还包括您自己构建的内容。)(-pedantic)。


8

如果你的代码需要可移植,那么你可以测试它是否编译时没有使用任何GCC扩展或其他非标准特性。如果你的代码能够通过-pedantic -ansi编译,那么理论上它应该可以在任何符合ANSI标准的编译器中编译通过。


4
-pedantic并不会关闭所有扩展,它会保留一些双下划线的东西。因此更准确的说法可能是,如果你的代码能够在使用-pedantic -ansi编译通过,并且看起来可能也可以在其他实现中编译通过,那么它就可以编译通过。 - Steve Jessop
4
你提到了双下划线的东西,听起来很有趣。你具体指的是什么? - huahsin68
3
一个例子是gcc的"asm()"内联汇编代码,这对于gcc来说很好,但是双下划线可能在其他编译器上不起作用,比如Windows编译器,即使该编译器符合标准。 - user2287171

4

如果你正在编写代码,并希望它能够在各种平台上编译,使用多个不同的编译器,则自己使用这些标志将有助于确保你不会生成仅在GCC下编译的代码。


2
在某些版本的GCC下! - Mohamed Amjad LASRI

3

其他人已经回答得足够详细了。我只想添加一些常见扩展的示例:

main函数返回void。这不是标准定义的,这意味着它只能在一些编译器上工作(包括GCC),但在其他编译器上不能工作。顺便说一下,int main()int main(int, char**)是标准定义的两个签名。

另一个流行的扩展是能够在其他函数内部声明和定义函数:

void f()
{
    void g()
    {
       // ...
    }

    // ...
    g();
    // ...
}

这是非标准的。如果你想要这种行为,可以查看C++11 lambdas

我认为标准严格定义了 int main(void)?但是 int main() 似乎总是被接受,即使使用 -pedantic。请参见 https://dev59.com/Ml4b5IYBdhLWcg3waA1P - qwr

0

Pedantic 让 GCC 编译器拒绝所有 GNU C 扩展,而不仅仅是使其符合 ANSI 标准的扩展。


1
这很有趣。您提到了GNU C扩展,这些扩展可能符合ANSI标准,也可能不符合。我可以获取更多相关信息吗?在哪里可以获得适当的资源? - huahsin68

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接