C、C99、ANSI C和GNU C之间有什么区别?

166

我开始在codechef上进行编程练习,但被C和C99之间的区别混淆了。这里的C是什么意思?是指C89吗?请查看此提交页面底部的语言选择。它包含C和C99两种。

我在网上找到了一个叫做GNU C的东西。linux/unix系统有不同于其他系统的C吗?它们是否符合ANSI的C标准?我还在一些地方看到过"严格的C99"。这是什么意思呢?

还有其他不同的C标准在使用吗?C4.3.2是什么?是当前使用的gcc版本吗?

编辑:

这个这个这个有所帮助。我会继续搜索并编辑未解答的问题。

我不是编程初学者。我知道什么是C语言。我知道ANSI有不同的C标准,如C89、C99和C11。


2
不要忘记 POSIX C :-) - pmg
5个回答

288
  • 标准化之前的一切通常被称为“K&R C”,这是根据著名书籍(第一版第二版)命名的,其中Dennis Ritchie是C语言的发明者之一。这是1972年至1989年的“C语言”。

  • 第一个C标准于1989年由美国国家标准协会ANSI在美国全国范围内发布。这个版本被称为C89或ANSI-C。从1989年到1990年,这是“C语言”。

  • 在此之后的一年,美国标准被国际接受并由国际标准化组织ISO发布(ISO 9899:1990)。这个版本被称为C90。从技术上讲,它与C89/ANSI-C是相同的标准。从形式上讲,它取代了C89/ANSI-C,使它们过时了。从1990年到1999年,C90是“C语言”。

    请注意,自1989年以来,ANSI与C语言无关,除了作为ISO标准的众多实例之一。现在在美国通过INCITS进行,C标准在美国正式称为INCITS/ISO/IEC 9899。就像在欧洲被称为EN/ISO/IEC一样。

    仍然谈论“ANSI C”的程序员通常对其含义一无所知。ISO通过标准ISO 9899“拥有”C语言。

  • 1995年发布了一个小的更新,有时被称为“C95”。这不是一个重大修订,而是一个名为ISO/IEC 9899:1990/Amd.1:1995的技术修正案。主要变化是引入了宽字符支持。

  • 1999年,C标准经历了一次重大修订(ISO 9899:1999)。这个版本的标准被称为C99。从1999年到2011年,这是“C语言”。

  • 2011年,C标准再次改变(ISO 9899:2011)。这个版本被称为C11。语言中添加了诸如_Generic_Static_assert和线程支持等各种新功能。这次更新主要关注多核、多处理和表达式排序。从2011年到2017年,这是“C语言”。

  • 2017年,C11进行了修订并解决了各种缺陷报告。这个标准非正式地称为C17或C18。它于2017年完成(并使用__STDC_VERSION__ = 201710L),但由ISO作为9899:2018发布,因此C17/C18之间存在歧义。它没有引入新功能,只是进行了修正。这是C语言的当前版本。

  • 一个名为“C23”或“C2X”的草案正在委员会进行中,计划于2023年发布(但官僚机构的轮子转动缓慢,请查看ISO的状态)。最新的工作草案N3096可以在这里找到。

    它包含了很多像C17/C18那样的小缺陷修复,但也包含了很多重大变化和新功能。这是一个重大版本。

    我在这里总结了最有可能影响普通C程序员的变化:C23是什么,我为什么要关心它?


"C99 strict"可能指的是编译器设置,强制编译器严格按照标准执行。C标准中有一个术语叫做“符合实现”。它的基本意思是:“这个编译器实际上正确地实现了C语言”。正确实现C语言的程序在形式上被称为“严格符合程序”。这样的程序也不能包含任何形式的模糊定义行为。
“GNU C”可以有两种含义。一种是指GNU编译器集合(GCC)中的C编译器本身。另一种是指GCC C编译器使用的非标准默认设置。如果你使用gcc program.c进行编译,那么你并不是按照C标准进行编译,而是使用了非标准的GNU设置,这可能被称为“GNU C”。例如,整个Linux内核是用非标准的GNU C编写的,而不是标准C。
如果你想按照C标准编译你的程序,你应该输入gcc -std=c99 -pedantic-errors。如果你的GCC版本支持,将c99替换为c17。

12
编译器的严格设置可能意味着“禁用扩展;只使用标准定义的C语言”,这一点与“正确编译”同样重要甚至更为重要。接受语言扩展是完全正确的;标准就是为了允许这样做而定义的。 - Eric Postpischil
5
还有C94/C95修正案1增加了更多的宽字符支持。另请参阅C和C++标准头文件列表 - Jonathan Leffler
2
你写道C90到C99发生了许多变化。您能否列举几个? - Martin Thoma
3
@Lundin,你提供的K&R书籍链接有误,这是第二版书,介绍的是C89标准。 - Antti Haapala -- Слава Україні
5
是的,但关键是那不是定义C编程语言的版本,即使它在任何地方出售也是如此。 - Antti Haapala -- Слава Україні
显示剩余2条评论

14

我必须就 ANSI C 作出回应。尽管ANSI没有做任何相关工作,但编译器仍然按照它构建。例如 PIC XC16 编译器: "该编译器是一款完全符合ANSI规范(ANSI x3.159-1989)所定义的 ANSI C 标准,并在 Kernighan 和 Ritchie 的《C程序设计语言》(第二版)中有所描述的经过验证的编译器……" 并非所有的编程都是针对像个人电脑这样的“大”计算机。 为您的设备编写编译器成本高昂,验证也需要时间和金钱。 ANSI C 在嵌入式/实时设备中仍然活跃且发展。


1
此外,如果某人正在维护一个使用二十年前编译器构建的嵌入式项目,通常最好继续使用二十年前的编译器而不是使用更新版本,除非在旧版编译器中发现了严重错误并在后来的版本中进行了修复。 - supercat
1
如果编译器供应商从使用专有编译器设计转向基于clang的设计,并且只有基于clang的编译器支持C11功能,那么这将是一个有力的论据,支持限制自己使用老旧编译器支持的功能,而不是更“现代”的编译器。 - supercat
值得注意的是,Microchip编译器以其差劲的标准符合性而臭名昭著。K&R第二版也不完全更新到“ANSI C”。现代所有嵌入式编译器现在都支持至少C11。我不会称各种PIC编译器为现代化的,我会称PIC为过时的CPU。是的,它仍在生产中,但核心很糟糕。如果您正在维护旧的垃圾代码,那么就是这样,我也维护着许多旧的8位垃圾代码。但是,如果要设计新产品,就不应该使用完全过时的MCU和完全过时的编译器。 - Lundin

6
除了Lundin的答案,下面是Dennis Richie在被问到以下问题时的回答:
“为什么K&R没有等待ANSI标准最终获得批准后再编写K&R第二版?”
块引用: 我们认为纪念第一版发行十周年是好的事情。更严肃的是,去年夏天我们开始着手准备,因为当时正值X3J11标准即将完成之际。在12月和1月份我们完成书稿时,我们考虑过是否有可能出现重大变化,这是否需要推迟交付。经过与出版商讨论后,我们决定不值得等待。P-H出版社想要这本书,并且我和Brian都希望把它从待办事项中删除。即使标准有所改变,也很难想象它们会足以导致新版。 (如果noalias仍然存在,我们甚至已准备好应对。)我们准备在未来的印刷中进行必要的更改,但有理由相信它们应该是次要的。 X3J11的成员非常渴望无意外地完成,许多人都在为准备ANSI编译器的公司工作。 Dennis Ritchie

2
很遗憾Dennis Ritchie没有意识到别名规则会被用来暗示编译器不应该做出任何努力去识别有用的别名形式,而是认为那些因为晦涩难懂的编译器而导致代码失效的程序员应该“感谢”编译器展示了他们的代码是“有缺陷”的--否则他本可以告诉那些推动这种规则的人明确表示拒绝支持超出标准最低要求的别名将使编译器不适用于某些目的,并且低级代码对别名的需求并不是一个缺陷。 - supercat
@supercat,我其实不太明白什么是别名规则,你能帮我解释一下吗? - Suraj Jain
2
最初的概念是,给定像 int i; int test(double *p) { i=1; *p=2.0; return i; } 这样的代码,编译器不需要在写入 *p 后重新加载 i,以防万一 p 可能持有 i 的地址。这是完全合理的。问题在于现代编译器使用相同的规则来证明对 long* 的写入不会影响 long long,即使两种类型具有相同的大小和表示形式,并且即使两个结构共享一个公共初始序列,代码也永远不会使用一个类型的指针来读取通过另一个类型写入的CIS成员。 - supercat

6
  • ANSI C:

    第一个C语言标准是由名为ANSI的机构在1989年制定,因此被称为c89。

  • C99:

    随着开发者需求的增加,在1999-2000年间C99中添加了进一步的关键字和功能(例如:inline,boolean...添加了浮点运算库函数)

  • GNU C:

    GNU是类Unix操作系统(www.gnu.org),某些GNU项目需要基于ANSI C标准的C编程语言。GNU使用GCC(GNU编译器集合)编译器来编译代码。它具有定义系统调用(如malloc,calloc,exit等)的C库函数。

ANSI C是被其他标准所引用或使用的标准。


任何关于 C99 strict 的内容,以及 CodeChef 中的 C 是 C89 还是早期的非标准原始 C。 - Aseem Bansal
1
更正:ANSI C是一个过时的标准,只有过时的文档才会提到它。C语言被称为ISO C,或者如果您愿意,可以称之为ISO/IEC 9899:2011。 - Lundin

-4

这个问题在网络上没有得到充分的搜索,但是您可以看一下以下内容:

  1. C语言是一种通用编程语言,最初由Dennis Ritchie在1969年至1973年间在AT&T Bell Labs开发。
  2. C99是ISO发布并被ANSI采纳的C语言标准,约于1999年发布。
  3. GNU C只是c89的扩展,虽然添加了c99的某些特性,但整体上与c99标准不同,因此在使用gcc进行编译时,我们必须输入-std=c99,这已经在其他答案中提到。
  4. ANSI C是由ANSI发布的一系列连续的标准。

我现在在网上搜索。我编辑了问题。在发布问题之前,我已经了解了C语言和ANSI标准。我对某些特定事物感到困惑。我会尽量更加精确。 - Aseem Bansal
关于C99 strict的任何内容,以及Codechef中的C是C89还是早期非标准化的原始C。 - Aseem Bansal
6
这个答案包含很多错误。C99是ISO在1999年左右定义的标准。C语言已经国际标准化了23年。因此,ANSI与此无关,他们已经24年没有涉及C标准了。现在,他们只是在美国市场上印刷和分发ISO标准。 - Lundin
@Lundin 哦!!是的,实际上我写的是“defined”,这不是事实,应该是“adopted”。我进行了更正。ANSI在1989年发布了C语言的第一个标准,后来被ISO采纳。此后,几乎所有的标准都是由ISO发布并由ANSI采纳的。既然问题要求回答简明扼要,所以我只提到了一些必要的事项。 - 0decimal0
1
请注意,gcc 支持 -std=c89-std=gnu89-std=c99-std=gnu99(现代版本还支持 -std=c11-std=gnu11)。区别在于标准 C 的扩展是否自动可用,或者只有当源代码使用适当的宏(例如 -D_XOPEN_SOURCE=700)促使编译器提供它们时才可用。 - Jonathan Leffler

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