C编译器在未指定类型时不抛出错误

为什么以下程序不会抛出错误:

dfljshfksdhfl; #include  int main () { return 0; } 

gcc会发出警告:

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

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

 dfljshfksdhfl; 

最终相当于:

 int dfljshfksdhfl; 

clang默认为我们提供了更多信息警告:

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

我们可以使用-pedantic-errors标志将其转换为错误,虽然奇怪的是这对clang不起作用,所以我们不得不求助于-Werror并将所有警告变成错误,这实际上是一个很好的习惯。 。 正如remyabel指出clang我们也可以使用-Werror=implicit-int

我已经回答了类似的问题 (实际上我很确定它是重复的,但无论如何),答案可以在C99理论中找到。

C99的新function:

在C89中,声明中的声明说明符可以省略所有类型说明符。 在这种情况下,暗示了int。 委员会认为,这一特征的内在危险性超过了它的便利性,因此被删除了。 其结果是保证生成可以捕获其他类别编程错误的诊断。 在发出诊断之后, 实现可以选择假设隐式int并继续转换程序以支持利用此function的现有源代码。

@ Shafik的答案告诉你一种方法将警告变为错误(对于Clang)。 如果您认为-Werror过于严格,可以使用-Werror=implicit-int警告转换为错误。 在海湾合作委员会中,似乎有-pedantic-errors

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

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

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

如果预处理转换单元或转换单元包含违反任何语法规则或约束的情况,则符合的实现应生成至少一个诊断消息(以实现定义的方式标识),即使该行为也明确指定为未定义或实现 – 定义。 在其他情况下不需要产生诊断消息。

非致命警告符合“诊断消息”的条件。 符合标准的C编译器可以为任何错误打印警告 – 甚至是语法错误 – 然后继续成功编译源文件。 (这是支持某些特定于编译器的语言扩展的方式。)

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

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