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

35g0bw71  于 2023-04-11  发布在  其他
关注(0)|答案(8)|浏览(221)

This note说:
-ansi:告诉编译器实现ANSI语言选项。这将关闭GCC的某些与ANSI标准不兼容的“功能”。
-pedantic:与-ansi一起使用,这告诉编译器严格遵守ANSI标准,拒绝任何不符合的代码。
先说重要的事

  • GCC/G++编译器的-pedantic-ansi选项的用途是什么(我无法理解上面的描述)?
  • 在什么情况下使用这两个选项是正确的?
  • 我应该什么时候使用它们?
  • 它们重要吗?
bmp9r5qi

bmp9r5qi1#

我在编码中一直使用它。
-ansi标志等同于-std=c89。如上所述,它关闭了GCC的一些扩展。添加-pedantic会关闭更多扩展并生成更多警告。例如,如果您的字符串文字长度超过509个字符,则-pedantic会对此发出警告,因为它超过了C89标准要求的最小限制。也就是说,每个C89编译器必须接受长度为509的字符串;它们被允许接受更长的字符串,但是如果你是学究式的,使用更长的字符串是不可移植的,即使编译器被允许接受更长的字符串,并且没有学究式的警告,GCC也会接受它们。

tvokkenx

tvokkenx2#

如果可能的话,GCC编译器总是会尝试编译你的程序。然而,在某些情况下,C和C标准指定禁止某些扩展。当遇到这些扩展时,GCC或g等符合标准的编译器必须发出诊断。
例如,GCC编译器的 -pedantic 选项会导致GCC在这种情况下发出警告。使用更严格的 -pedantic-errors 选项会将这种诊断警告转换为错误,从而导致编译失败。只有那些需要由符合标准的编译器标记的非ISO结构才会生成警告或错误。

chhkpiq4

chhkpiq43#

-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之外,[ and ]还可以分隔表达式或 *。如果它们分隔表达式(指定数组的大小),则表达式应具有整数类型。如果表达式是常量表达式,则应具有大于零的值。[...]
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++,听起来很愚蠢。

46qrfjad

46qrfjad4#

基本上,它将使您的代码更容易在其他编译器下编译,这些编译器也实现了ANSI标准,并且如果您小心使用的库/API调用,则在其他操作系统/平台下编译。
第一个关闭GCC的 * 特定 * 功能(-ansi)。
第二个人会抱怨任何不符合标准的东西(不仅是GCC的特定功能,还有你的构造)(*-迂腐 *)。

ia2d9nvy

ia2d9nvy5#

如果你的代码需要 * 可移植 *,那么你可以测试它在没有任何GCC扩展或其他非标准功能的情况下编译。如果你的代码用-pedantic -ansi编译,那么理论上它应该可以用任何其他ANSI标准编译器编译。

gtlvzcf8

gtlvzcf86#

如果您正在编写的代码预计将在各种各样的平台上编译,使用许多不同的编译器,那么自己使用这些标志将有助于确保您不会生成仅在GCC下编译的代码。

oknwwptz

oknwwptz7#

其他人的回答已经足够了。我只想补充几个频繁扩展的例子:
main函数返回void。这不是标准定义的,这意味着它只在某些编译器上工作(包括GCC),而不是在其他编译器上。顺便说一下,int main()int main(int, char**)是标准定义的两个签名。
另一个流行的扩展是能够在其他函数中声明和定义函数:

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

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

这是非标准的。

mrzz3bfm

mrzz3bfm8#

学究气使得GCC编译器拒绝所有的GNU C扩展,而不仅仅是那些使其ANSI兼容的扩展。

相关问题