如何禁用GNU C扩展?

13

如您在以下代码中所见,我已在main()函数内引入了一个嵌套函数:

#include <stdio.h>

int main(){
 int a=5;
 printf("%d\n",a);
 {
  int a=10;
  printf("%d\n",a);
 }
 printf("%d\n",a);

 //Nested function
 int main(int a){
 if(a>0)printf("%d\n",a--);
 return 0;
 }

 main(7);
 return 0;
}

据我理解,我在gcc中使用-std=c99标志来“禁用”不必要的扩展功能,但我没有收到任何错误信息。

gcc temp3.c -std=c99 -o temp3.out

我犯了什么错误?


5
加上-pedantic -Werror应该可以解决这个问题。 - Jonathan Leffler
那么,-std=c99标志有什么用处? - Mayank Verma
-std=c99 标志禁用了 GCC 认为应该被禁用的 GNU 扩展,例如 POSIX 版本等。请参阅 C 语言方言选项 以了解 -std= 的含义;请参阅 警告选项 以了解 -pedantic 的含义。 - Jonathan Leffler
1个回答

20
  • 在命令行中添加-pedantic-Werror

在Mac OS X 10.11.6上使用GCC 6.1.0,将您的原始代码保存在文件ped73.c中,并使用我的默认编译选项,我得到以下结果:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition ped73.c -o ped73 
ped73.c:3:5: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
 int main(){
     ^~~~
ped73.c: In function ‘main’:
ped73.c:3:5: error: old-style function definition [-Werror=old-style-definition]
ped73.c:13:6: error: ‘main’ takes only zero or two arguments [-Werror=main]
  int main(int a){
      ^~~~
ped73.c:13:6: error: ‘main’ is normally a non-static function [-Werror=main]
$

将嵌套函数重命名为“nested”,并使用“int main(void)”,我得到了以下结果:
$ gcc -O3 -g-std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes 
>     -Wold-style-definition -o ped73
$

使用额外的选项-pedantic,我得到:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -pedantic ped73.c -o ped73 
ped73.c: In function ‘main’:
ped73.c:13:2: error: ISO C forbids nested functions [-Werror=pedantic]
  int nested(int a){
  ^~~
cc1: all warnings being treated as errors
$

那么,-std=c99 有什么意义呢?

-std=c99 标志禁用了 GCC 认为应该禁用的 GNU 扩展,例如 POSIX 版本等。请参见 C 语言方言选项 以了解 -std= 的含义;请参见 警告选项 以了解 -pedantic 的含义。

-Wpedantic
-pedantic

发出严格的ISO C和ISO C++所要求的所有警告,拒绝使用禁止扩展以及一些不符合ISO C和ISO C++规范的程序。对于ISO C,遵循任何使用-std选项指定的ISO C标准版本。

有效的ISO C和ISO C++程序应该可以在有或没有此选项的情况下正确编译(尽管极少数需要-ansi或指定所需ISO C版本的-std选项)。但是,如果没有此选项,则还支持某些GNU扩展和传统C和C++特性。启用此选项后,它们将被拒绝。

-Wpedantic不会导致针对使用以__开头和结尾的备用关键字的警告消息。严格的警告也会在跟随__extension__的表达式中禁用。但是,只有系统头文件应该使用这些逃生路线;应用程序应避免使用它们。请参阅备用关键字。

一些用户尝试使用-Wpedantic检查程序是否符合严格的ISO C规范。他们很快发现它并不完全符合他们的要求:它找到了一些非ISO实践,但并不是所有的——只有那些需要ISO C诊断的实践,以及添加了一些其他诊断的实践。

报告任何未遵守ISO C的功能的功能在某些情况下可能很有用,但需要进行相当多的额外工作,并且与-Wpedantic截然不同。我们没有计划在近期支持这样的功能。

如果使用-std指定的标准表示C的GNU扩展方言,例如“gnu90”或“gnu99”,则存在相应的基本标准,即基于GNU扩展方言的ISO C版本。在需要基本标准的警告处提供-Wpedantic的警告。(仅针对指定的GNU C方言中不存在的功能提供此类警告是没有意义的,因为按定义,C的GNU方言包括编译器支持的所有功能,给出警告没有任何意义。)

还有一种不同的选项可以提供学究式的错误:

-pedantic-errors

每当基本标准(参见-Wpedantic)需要诊断时,都会发生错误,在某些情况下,编译时存在未定义的行为,在其他一些情况下,这不会阻止根据标准有效的程序的编译。 这与-Werror=pedantic不等效,因为此选项启用了某些错误,而后者没有启用,反之亦然。


有很多关于使用哪些GCC编译器选项的问题,包括:

毫无疑问,还有许多其他可以添加到该列表中的问题。基本上,我使用的默认选项确保在使用函数之前声明它们(或者在使用之前将其定义为static函数),并且函数声明具有完整的原型 - 没有空括号() - 并使用-Wall-Wextra来检测许多其他常见问题,包括printf()scanf()函数族中格式字符串和参数之间的不匹配。


当我将-pedantic添加到我的默认编译字符串时,我偶然发现了这个问题。我唯一找到它记录的地方是GCC支持的语言标准 - David C. Rankin
1
可能需要强调并解释一下你对-Wall -Wextra的使用。这会导致编译器报告各种默认未配置的问题。其中并非所有问题都与避免gcc扩展有关,但它们是指示错误(可疑转换等)或在其他编译器中无法按预期工作的问题。如果-Werror不会在警告时终止,那么“不接受触发警告的代码”的明确策略将会生效。 - Peter
2
这仍然不禁用gnu扩展,除了那些与语法相关的扩展。例如,通过联合进行类型转换仍然有效,并且即使在此模式下也是允许的。 - Swift - Friday Pie
我不认为这回答了问题。将所有警告转换为错误与禁用GNU扩展不同。想象一下我作为教师的工作,试图自动化部分练习提交过程,不希望看到使用GNU扩展,但也不希望因其他警告而停止编译。 - Tammi
你无法完全停止GNU扩展。没有提供任何机制来实现这一点。这是你能够做到的最接近的方式。 - Jonathan Leffler

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