我只是尝试使用GNU编译器版本4.9.2编译C程序。源代码包含一些for int i=0; ...
语句,编译器给了我一个错误,并指出我应该使用-std=c99
来编译循环初始声明。显然,这些声明在C99之前无效。
在另一台机器上,我有一个更新的GNU编译器(8.1.1),我可以编译相同的源代码而无需显式指定-std=c99
。
因为GNU显然使他们的编译器C99在4.9.2和8.1.1之间兼容,这引出了一个问题,即最近的C标准是否指定编译器必须遵守C99(或其他标准)。
选择是否遵守C标准或其特定版本是自愿的。选择不是来自C标准。它来自外面。任何进行C实现的人都决定是否符合2018 C标准(或者主要是符合但不完全符合),是否符合2011 C标准,是否符合C的某些“K&R”概念或其他内容。 C标准中没有任何内容表明,如果您符合此标准,您的编译器必须符合以前的某些版本。在您选择符合标准之前,标准实际上不需要您做任何事情。
C标准以及制定它的人和支持和发布它的标准组织几乎没有权力让任何人做任何事情。他们不能发布C标准并且说你René Nyffenegger必须遵守2018 C标准。他们不是立法机构。私人当事方之间有合同,称某些项目将按照该标准或该标准生产,但这些是私人协议,而非公法。
在2018 C标准中,前言第8段说:
有关标准的自愿性质的解释,与合格评定相关的ISO特定术语和表达的含义,以及ISO在技术性贸易壁垒(TBT)中遵守世界贸易组织(WTO)原则的信息,请参阅以下网址:www.iso.org/iso/foreword.html。
标准组织也不能禁止您编写符合或不符合标准的任何特定版本的C编译器,也不禁止编写符合但不完全符合的编译器。
如果您在商业上使用C标准的名称,也许通过声称符合它,标准组织可能在这方面拥有一些合法权利。这涉及国际法和许多司法管辖区的法律,我不能权威地谈及这些法律。我没有听说过声称符合C标准的人有任何问题。
当新版本发布时,标准组织会正式撤销旧版本的标准。这不会阻止您编写符合旧版本的C实现,但是如果不这样做,它将阻止您声明您符合当前版本。 (例如,如果您同意的合同要求您遵守当前的C标准,那么当组织发布新版本并撤销旧版本时,这将会改变。)
在GCC 5.0之前,它遵守(最接近)的默认标准是C90标准 - 指定没有标准等同于指定-std=gnu90
。
从5.0开始,默认值更改为C11标准 - 因此指定无标准等同于指定-std=gnu11
。
您的两个编译器版本显示此行为。
请注意,C标准仅规定了编译器必须遵守该标准的内容。它不强制编译器对标准的先前版本或未来版本的行为;就标准而言,标准只有一个版本。编译器实现对其他版本的作用完全取决于编译器编写者。
当然,您可以使用显式版本覆盖GCC的默认行为:
-ansi
-std=c90
-std=c99
-std=c11
-std=gnu90
-std=gnu99
-std=gnu11
-ansi
选项相当于-std=c90
。 -std=cXX
和-std=gnuXX
之间的区别在于c
版本没有为各种扩展设置宏,因此您可能必须明确指出您要使用POSIX接口,例如,使用-D_XOPEN_SOURCE=700
等选项,而使用gnu
版本自动设置这些宏。
C标准的每个版本将实现分为两类:符合标准特定版本的那些,以及不符合特定版本的那些。没有任何C语言警察会打破任何出售不合规执行人员的膝盖。实际上,在某些情况下,不符合要求的实现比任何符合要求的实现都更有用(例如,在某些小型嵌入式平台上,生成完全符合“printf”实现所需的代码量可能超过总代码可用空间)。此外,无法保证每个符合要求的实施都适用于任何特定目的(事实上,除了证明C标准不强制使用之外,有可能设计出不适用于任何目的的C实施) 。
大多数高质量的C开发系统可以以不同的模式调用,这些模式可能符合(或不符合)标准的不同版本,并且可能适合(或不适合)用于各种目的。从标准的角度来看,可以调用开发系统的每种不同模式都是不同的实现。我认为让标准对实现进行子分类是有用的,这些实现是基于它们支持(或缺乏)实现流行特性或保证,使它们适合(或不适合)用于常见目的(例如低级或系统编程)但到目前为止标准还没有这样做。