是自动的;一个有效的C翻译单元?

是自动的;一个有效的C翻译单元?,c,gcc,clang,C,Gcc,Clang,创建一个包含以下代码的文件test.c: auto; 用clang6.0编译它:clang-c test.c。它将成功生成一个对象文件test.o,尽管该文件没有实际内容(对象文件头除外)。它会打印一条警告,但仍会将其作为有效代码接受: test.c:1:1: warning: declaration does not declare anything [-Wmissing-declarations] auto; ^~~~ 1 warning generated. 相比之下,GCC4.9拒绝

创建一个包含以下代码的文件
test.c

auto;
用clang6.0编译它:
clang-c test.c
。它将成功生成一个对象文件
test.o
,尽管该文件没有实际内容(对象文件头除外)。它会打印一条警告,但仍会将其作为有效代码接受:

test.c:1:1: warning: declaration does not declare anything [-Wmissing-declarations]
auto;
^~~~
1 warning generated.
相比之下,GCC4.9拒绝编译
test.c
,产生错误:

test.c:1:1: error: 'auto' in file-scope empty declaration
 auto;
 ^

为什么clang生成一个警告,而gcc生成一个错误并拒绝编译它,却接受这个翻译单元为有效的?谁的行为更符合C标准?允许不声明任何内容的自动声明有什么意义?

这是无效代码。但在发出诊断消息后,该实现可以自由赋予它任何想要的含义

5.1.1.3诊断 1一致性实施应产生至少一条诊断信息(在 一种实现定义的方式)如果是预处理翻译单元或翻译单元 包含违反任何语法规则或约束的行为,即使该行为也是显式的 指定为未定义或实现已定义。诊断消息不需要 在其他情况下产生。9)
[……]

6.7声明 约束
2除静态声明之外的声明应至少声明一个声明人 (函数参数或结构或联合的成员除外)、标记,或 枚举的成员。
[……]


引用C99+修正案(C11、n1570)

当然,只有错误意味着代码无效,而警告意味着该代码可能很危险,没有做你认为它做的事情,没有做任何有用的事情,等等,但在技术上不是无效的。两者都会发出诊断,因此两者都同样符合标准。(除非允许,否则只有叮当声才符合。但事实并非如此。)@重复数据消除器:就标准而言,失败的
\u Static\u assert
#error
都只需要诊断(它们与任何其他形式的约束冲突或语法错误没有区别)。§5.1.2.2/1:“如果预处理翻译单元或翻译单元包含违反任何语法规则或约束的行为,即使行为也明确指定为未定义或实现定义,一致性实现应产生至少一条诊断消息(以实现定义的方式识别)。在其他情况下不需要生成诊断消息。“@mafso:不正确(尽管很容易漏掉,因为第6.10.5节描述了
#error
,没有提到这一点)。第4节第4段说:除非预处理翻译单元是被条件包含跳过的组的一部分,否则实现不能成功翻译包含
#error
预处理指令的预处理翻译单元。“我没有看到类似的
\u Static\u assert
语句。参考:。您已经从标准的角度回答了我的问题,谢谢。但是,我仍然试图理解的是,为什么gcc开发人员做了一件事,而叮当作响的开发人员做了另一件事。我假设他们在判断某件事是错误还是警告时,不会只是掷硬币。gcc的方法似乎更符合逻辑,只是不一致的是,gcc只对“auto;”和“register;”存储类出错,而“typedef;”、“extern;”和“static;”只是警告(如clang)。@Simon clang决定使用
-fcolor diagnostics
和gcc
-fdiagnostics color
的原因也是如此。因为他们喜欢这样。有时你可以在邮件列表或bug追踪器中找到原因(但这需要一点搜索)