为什么C有下划线开头的关键字

Why does C have keywords starting with underscore

大多数 C 语言(或与此相关的任何语言)的关键字都以字母开头。但是有一些关键字是下划线开头的吗?它们的关键字是:_Alignas_Alignof_Atomic_Bool_Complex_Generic_Imaginary_Noreturn_Static_assert_Thread_local.

我觉得很奇怪。如果它是一个隐藏的全局常量或内部函数,而不是 API 的一部分,我会理解的。但这些是 关键字

当 C 实际上有一个名为 boolstatic_assert 的宏并且它们的实现使用的正是我刚才提到的关键字时,我觉得特别奇怪。

在标准中,任何以双下划线或下划线后跟大写字母开头的名称都是保留的。这很有用,因为 C 缺少命名空间。通过保留所有此类符号,可以将新的和特定于实现的关键字引入语言,而不会与现有代码中定义的符号发生冲突。

boolstatic_assert等宏是“便捷宏”,它们允许您使用不带下划线和大写字母的保留关键字符号名称冲突的风险很小。然而,它们提供了一种解决名称冲突的方法,因为与关键字不同,宏可能被 #undefined,或者定义它的 header 被排除并直接使用内部关键字。此外,未修改的遗留代码不会被破坏,因为根据定义,它不会包含在编写

时不存在的 header

朴实无华的关键字自语言诞生以来就已在语言中定义(除了自 C99 以来定义的 inlinerestrict),因此不会与遗留代码符号发生冲突。所有 _Xxxx 关键字都是在 C99 或之后定义的。

与当今常用的许多语言不同,C 自 1970 年代就已存在并自 1989 年起标准化 - 大量现有代码必须在现代编译器上保持可编译性,同时语言不能保持不变- 如果它确实存在,它可能不再被如此普遍使用。

C 在标准委员会计划之前就已经发展起来并变得非常流行。结果,有很多现有代码。

制定 C 标准或更新旧标准时,一个重要的目标是不要“破坏”旧代码。希望适用于以前编译器的代码继续适用于新版本的 C 语言。

引入新关键字(或任何新的定义或词义)可能会破坏旧代码,因为在编译时,该词将具有新的关键字含义,而不是它在以前的编译器中具有的标识符含义。必须编辑代码。除了花钱请人编辑代码之外,如果出现任何错误,这还有引入错误的风险。

为了解决这个问题,制定了一个规则,保留以下划线开头的标识符。制定这条规则并没有破坏很多旧软件,因为大多数编写软件的人选择使用以字母开头的标识符,而不是下划线。这条规则赋予了 C 标准一个新的能力:通过在添加新关键字或单词的其他新含义时使用下划线,只要旧代码遵守规则,就可以在不破坏旧代码的情况下这样做。

C 标准的新版本有时会为不以下划线开头的单词引入新的含义,例如 bool。但是,这些新含义一般不会在核心语言中引入。相反,它们仅在新的 header 中引入。在制作 bool 类型时,C 标准提供了新的 header、<stdbool.h>。由于旧代码不能包含 <stdbool.h> 因为它在编写代码时不存在,所以在 <stdbool.h> 中定义 bool 不会破坏旧代码。同时,它使编写新代码的程序员能够通过包含 <stdbool.h>.

使用新的 bool 功能

Eric 和 Clifford 提供了很好的答案,但我添加了 C11 标准的引述来支持它。

  • All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
  • All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.

https://port70.net/~nsz/c/c11/n1570.html#7.1.3

也可以考虑这个:

Typedef names beginning with int or uint and ending with _t may be added to the types defined in the stdint.h header. Macro names beginning with INT or UINT and ending with _MAX, _MIN, or _C may be added to the macros defined in the stdint.h header.

https://port70.net/~nsz/c/c11/n1570.html#7.31.10p1