当未指定类型时,C编译器未引发错误



为什么下面的程序没有抛出错误:

dfljshfksdhfl;
#include <stdio.h>
int main () {
        return 0;
}

gcc只会发出警告:

test.c:1:1:警告:数据定义没有类型或存储类[默认启用]

这是因为即使隐式int自C99以来不再是C标准的一部分,一些编译器仍然支持它,主要是为了防止破坏许多旧代码。所以这行:

dfljshfksdhfl;

最终相当于:

int dfljshfksdhfl;

默认情况下,clang会给我们一个信息量更大的警告:

warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
dfljshfksdhfl;
^~~~~~~~~~~~~

我们可以使用-pedantic errors标志将其转化为错误,尽管奇怪的是,这对clang不起作用,因此我们不得不求助于-Werror并将所有警告转化为错误——这实际上是一个很好的习惯。正如雷米亚贝尔指出的clang,我们也可以使用-Werror=implicit-int

我已经回答了一个类似的问题(实际上我很确定这是重复的,但不管怎样),答案在C99的基本原理中。

C99的一个新特性:

在C89中,所有类型说明符都可以从声明中省略声明中的说明符。在这种情况下,隐含了int。这个委员会决定,这一特点的内在危险性大于它的便利性,因此它被移除了。其效果是保证生成将捕获附加类别的诊断编程错误。发布诊断后,执行可以选择采用隐式int并继续翻译程序,以便支持利用此漏洞的现有源代码功能

@沙菲克的回答告诉你一种将警告变成错误的方法(对于Clang)。如果您认为-Werror过于严格,则可以使用-Werror=implicit-int将该警告转化为错误。在GCC中,似乎-pedantic-errors是必要的。

首先,gcc默认情况下不是一个合格的C编译器。它使用GNU扩展实现了C89/C90的方言。

可以使用-std=cNN -pedantic(其中NN可以是909911)使其(尝试)符合指定版本的ISO C标准。C90允许隐式CCD_ 15;它在C99中被丢弃。

但C编译器实际上并不需要来生成致命错误消息(#error指令除外)。该标准的要求(N1570 5.1.1.3p1)为:

一致性实施应至少产生一个诊断如果预处理翻译单元或翻译单元包含违反任何语法规则或约束,即使行为也明确指定为未定义或实现定义。在其他情况下不需要生成诊断消息。

非致命性警告属于"诊断消息"。一致的C编译器可以为任何错误(甚至语法错误)打印警告,然后继续成功地编译源文件。(这就是支持某些编译器特定语言扩展的方式。)

就我个人而言,我发现gcc对某些错误过于松懈;在我看来,丢失的int应该被视为致命错误。但这只是我的偏好,而不是标准强加的要求。

这里的教训是,你不应该认为仅仅是警告是无害的。理想情况下,编译代码应该不会产生任何诊断。忽略警告的情况很少见(但它们确实存在,因为编译器可以自由地警告完全有效的代码)。

最新更新