Lun*_*din 50 c c++ language-lawyer c-standard-library
注意:这是一个c问题,但我添加了c ++,以防一些C++专家可以提供C++使用与C不同的措辞的基本原理或历史原因.
在C标准库规范中,我们有这个规范性文本,C17 7.1.3保留标识符(强调我的):
- 所有以下划线开头的标识符以及大写字母或另一个下划线始终保留用于任何用途.
- 所有以下划线开头的标识符始终保留用作普通和标记名称空间中具有文件范围的标识符.
现在我继续阅读各种受尊敬的C专家的答案,他们声称编译器或标准库可以使用下划线+大写或双下划线的标识符.
是否"保留用于任何用途"是指保留给除C语言本身的未来扩展之外的任何人?这意味着实现不容许使用它们.
虽然上面的第二个短语,关于单个前导下划线似乎是针对实现?
通常,C标准的编写方式要求编译器供应商/库实现者是典型的读者 - 而不是应用程序员.
值得注意的是,C++的措辞非常不同:
- 每个包含双下划线(
__)或以下划线后跟大写字母(2.11)开头的名称都保留给实现以供任何使用.
(请参阅在C++标识符中使用下划线有哪些规则?)
这可能是C和C++之间的混淆,语言在这里有所不同吗?
zwo*_*wol 33
在C标准中,术语"保留"的含义由7.1.3p2定义,紧接在您引用的项目符号列表下方:
没有保留其他标识符.如果程序在保留它的上下文中声明或定义标识符(除了7.1.4允许的标识符),或者将保留标识符定义为宏名称,则行为是未定义的.
强调我的:保留标识符对程序有限制,而不是实现.因此,通用解释 - 保留标识符可以由实现用于任何目的 - 对于C是正确的.
我没有跟上C++标准,也不再觉得有资格解释它.
Sne*_*tel 16
虽然标准主要是为指导实施者编写的,但它是作为对程序格式良好的描述及其效果的描述而编写的.那是因为符合标准的编译器的基本定义是为任何符合标准的程序做正确的事情:
严格符合的程序应仅使用本国际标准中规定的语言和库的特征....符合要求的托管实现应接受任何严格符合的程序.
单独阅读,这是对编译器扩展的极大限制.例如,仅基于该子句,编译器不应该定义任何自己的保留字.毕竟,特定编译器可能想要保留的任何给定单词仍然可以出现在严格符合的程序中,从而迫使编译者动手.
然而,标准还在继续:
符合实现的实现可能具有扩展(包括附加库函数),前提是它们不会改变任何严格符合程序的行为.
这是关键部分.编译器扩展需要以这样的方式编写,即它们影响不合格的程序(包含未定义的行为,或者根本不应该编译的程序),允许它们编译并做有趣的额外事情.
因此,当语言实际上不需要那些标识符时,定义"保留标识符"的目的是通过向实现提供使程序不一致的一些内容来为实现提供一些额外的摆动空间.编译器可以识别,例如,__declspec作为声明的一部分的原因是因为放入__declspec声明是非法的,因此允许编译器做任何想做的事情!
因此,"保留用于任何用途"的重要性在于,它不会对编译器将此类标识符视为具有其关注的任何含义的权力留下任何疑问.未来的兼容性是一个相对遥远的问题.
C++标准以类似的方式工作,尽管它对开局有点明确:
符合条件的实现可能具有扩展(包括其他库函数),前提是它们不会改变任何格式良好的程序的行为.需要实现来诊断使用根据本国际标准格式不正确的扩展的程序.但是,这样做之后,他们就可以编译和执行这样的程序.
我怀疑措辞上的差异取决于C++标准,只是更清楚地知道扩展是如何工作的.然而,C标准中没有任何内容阻止实现做同样的事情.(而且我们基本上都忽略了编译器每次使用时都会发出警告的要求__declspec.)
Lun*_*din 12
关于C与C++中措辞的区别,我在这里发布我自己的小研究作为参考:
早期的K&R C第1版有这样的文字:
...仅供库的功能使用的名称以下划线开头,因此它们不太可能与用户程序中的名称冲突.
K&R第二版增加了附录B,其中涉及标准库,我们可以在这里阅读
以下划线开头的外部标识符保留供库使用,所有其他标识符以下划线和大写字母或另一个下划线开头.
早期的ANSI C草案以及"C90"ISO 9899:1990具有与当前ISO标准相同的文本.
然而,最早的C++草案有一个不同的文本,如@hvd所述,可能是对C标准的澄清.摘自1994年9月20日:
17.3.3.1.2全局名称
...
以下划线开头,以大写字母或另一个下划线(2.8)开头的每个名称都保留给实现以供任何使用
显然,"保留用于任何用途"的措辞是由ANSI/ISO C90委员会发明的,而C++委员会在几年后使用了更清晰的措辞,类似于预标准K&R书中的措辞.
C99基本原理V5.10在7.1.3下面说:
同样为实现者保留的是所有外部标识符,以下划线开头,所有其他标识符以下划线开头,后跟大写字母或下划线.这给了一个名称空间,用于编写大量的幕后非外部宏和库需要正常工作的函数.
这使得委员会的意图非常明确:"保留用于任何用途"意味着"为实施者保留".
另外值得注意的是,目前的C标准在其他地方的6.2.5中有以下规范性文字:
也可能存在实现定义的扩展有符号整数类型.38)
信息足迹38说:
38)实现定义的关键字应具有为7.1.3中描述的任何用途保留的标识符的形式.
C 有多个上下文,其中符号可以有定义:
“保留供任何使用”意味着兼容程序中的用户代码不能在上述任何上下文中使用以下划线开头后跟大写字母或另一个下划线的1符号。与以单个下划线开头但后跟小写数字或数字的标识符进行比较。这属于以下划线开头的第二类标识符。用户代码可以使用这些标识符作为宏参数的名称、标签或结构/联合成员的名称。
“保留供任何使用”并不意味着实现不能使用此类符号。保留的目的是提供一个实现可以自由使用的名称空间,而不必担心实现定义的名称会与兼容程序中用户代码定义的名称冲突。
1该标准并不完全意味着“不能使用”。该标准鼓励以编程方式使用少量以双下划线开头的名称。例如,需要一个兼容的实现来定义__STDC_VERSION__、__FILE__、__LINE__和__func__。该标准的 2011 版本甚至给出了一个引用__func__.