“保留任何使用权”是什么意思?

时间:2018-09-17 12:13:11

标签: c++ c language-lawyer c-standard-library

注意:这是一个问题,尽管我添加了,以防某些C ++专家可以提供C ++使用与C不同的措辞的理由或历史原因。


在C标准库规范中,我们有以下规范性文字C17 7.1.3保留标识符(强调我的名字):

  
      
  • 所有以下划线开头,大写字母或另一个下划线的标识符始终保留供任何使用
  •   
  • 所有以下划线开头的标识符始终保留用作普通和标记名称空间中文件范围的标识符。
  •   

现在,我继续阅读各种知名C语言专家的SO解答,他们声称编译器或标准库可以使用带下划线+大写或双下划线的标识符。

除了将来对C语言本身的扩展之外,“保留任何用途”是否意味着保留给任何人?这意味着不允许使用该实现。

虽然上面的第二个短语似乎是关于单引号的下划线?

通常,C标准的编写方式希望编译器供应商/库实现者是典型的读者,而不是应用程序程序员。

值得注意的是,C ++的措辞非常不同:

  
      
  • 每个名称都包含双下划线(__)或以下划线开头的大写字母(2.11)保留给实现以供任何使用
  •   

(请参见What are the rules about using an underscore in a C++ identifier?

这也许是C和C ++之间的混淆,并且这里的语言不同吗?

6 个答案:

答案 0 :(得分:33)

在C标准中,“保留”一词的含义由7.1.3p2定义,在您引用的项目符号列表的正下方:

  

没有其他标识符保留。如果程序在保留它的上下文中声明或定义标识符(而不是7.1.4允许),或者将保留标识符定义为宏名,则行为未定义。

强调点:保留的标识符对程序而不是对实现施加了限制。因此,通用解释(保留标识符可被实现用于任何目的)对于C是正确的。

我没有跟上C ++标准,也没有资格去解释它。

答案 1 :(得分:16)

虽然该标准主要是为指导实施者而编写的,但它是作为 的描述来描述使程序格式正确的内容以及其作用的说明。这是因为符合标准的编译器的基本定义对于任何符合标准的程序都是正确的事情:

  

严格遵守的程序应仅使用语言和库的那些功能   本国际标准中规定的...   托管实施应接受任何严格符合要求的程序。

单独阅读,这在很大程度上限制了编译器的扩展。例如,仅基于该子句,编译器不应定义自己的保留字 any 。毕竟,特定编译器可能会想要保留的任何给定单词,但仍会出现在严格符合要求的程序中,从而迫使编译器出手。

该标准仍在继续,

  

符合标准的实现可能会有扩展(包括其他   库函数),前提是它们不会更改任何严格符合的行为   程序。

那是关键。编译器扩展的编写方式应使它们影响 conconforming 程序(包含未定义行为的程序,甚至根本不应该编译的程序),从而使它们能够进行编译并做一些有趣的事情。

因此,当语言实际上不需要 标识符时,定义“保留标识符”的目的是通过为实现提供一些东西,从而为实现提供一些额外的摆动空间程序不合格。编译器之所以可以将__declspec识别为声明的一部分,是因为将__declspec放入声明中是非法的,因此允许编译器做任何想做的事!

因此,“保留任何用途”的重要性在于,毫无疑问,编译器将这些标识符视为具有其所关心的含义的能力。未来的兼容性是一个相对遥远的问题。

C ++标准以类似的方式工作,尽管它在技巧上更为明确:

  

符合条件的实现可能具有扩展(包括其他库函数),前提是它们具有   不会改变任何格式正确的程序的行为。需要实施才能诊断程序   使用根据本国际标准格式不正确的扩展名。 但是,   他们可以编译并执行此类程序。

我怀疑在措辞上的差异取决于C ++标准,只是更加清楚了扩展的工作方式。但是,C标准中没有任何东西可以阻止实现执行相同的操作。 (而且我们基本上都忽略了每次使用__declspec时编译器都会警告您的要求。)

答案 2 :(得分:12)

关于C和C ++措辞的区别,我在这里发表自己的小论文作为参考:

  • 早期K&R C 1st edition的文字如下:

      

    ...仅供库函数使用的名称以下划线开头,因此它们不太可能与用户程序中的名称冲突。

  • K&R第二版添加了附录B,该附录B解决了我们可以阅读的标准库

      

    以下划线开头的外部标识符保留给库使用,就像所有   以下划线和大写字母或另一个下划线开头的其他标识符。

  • 早期的ANSI C草案以及“ C90” ISO 9899:1990具有与当前ISO标准相同的文本。

  • 然而,@ hvd指出,最早的C ++草案具有不同的文本,可能是C标准的澄清。来自DRAFT: 20 September 1994

      

    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中进行了说明。

答案 3 :(得分:4)

C具有多个可以在其中定义符号的上下文:

  • 宏名称的空间,
  • 宏参数的形式名称空间(此空间特定于每个类似于函数的宏),
  • 普通标识符的空间
  • 标签名称的空间,
  • 标签的空间(此空间特定于每个功能),并且
  • 结构/工会成员的空间(此空间特定于每个struct /工会)。

“保留为任何用途”表示兼容程序中的用户代码不能使用以下划线开头,后跟大写字母或上述任何其他下划线的 1 符号上下文。与以单个下划线开头但后跟小写数字或数字的标识符进行比较。这属于以下划线开头的第二类标识符。用户代码可以可以将这些标识符用作宏参数的名称,标签或结构/联合成员的名称。

“保留供任何使用”并不意味着实现不能使用此类符号。保留的目的是提供一个名称空间,实现可以自由使用,而不必担心实现定义的名称将与兼容程序中用户代码定义的名称发生冲突。


1 该标准并不完全意味着“不能使用”。该标准鼓励以编程方式使用少量以双下划线开头的名称。例如,需要一种兼容的实现来定义__STDC_VERSION____FILE____LINE____func__。该标准的2011年版本甚至提供了一个引用__func__的大概兼容程序的示例。

答案 4 :(得分:2)

C标准允许实现将其认为合适的任何含义附加到保留标识符。当没有理由不这样做时,大多数实现将对待保留形式的无法识别的标识符与其他任何公认的标识符一样对待,从而允许执行以下操作:

#ifdef __ACME_COMPILER
#define near __near
#else
#define near
#endif

int near foo;

使用foo限定符声明标识符__near(如果代码是在Acme编译器中处理的(可能会支持这种事情),但也与其他不兼容的编译器兼容)要求使用此类指令或从中受益。没有什么会阻止合格的实现定义__ACME_COMPILER并解释__near来表示“发射核导弹”的意思,但是高质量的实现不应破坏上面的代码。如果实现不知道__ACME_COMPILER的含义,则将其像其他任何未知标识符一样对待,将允许它支持上述有用的构造。

答案 5 :(得分:0)

已经晚了几个月,但还有一点没有解决。

您的问题可以从相反的方向看。该标准允许实现(如您所观察到的)使用像_Foo这样的符号,但更重要的是,因此禁止该实现使用foo。后者保留供您的使用。

出于讨论的目的,要理解,假设将来的C标准引入了新关键字_Foo。假设的实现已经在使用该符号,那么会发生什么呢?

答案:

  1. 首先,该实现将尚未实现新标准。在实施之前,新标准还没有实际效果。

  2. 稍后,作为实施新标准的一部分,该实施会悄悄地将每个_Foo更改为_Bar

没问题。

实际上,如果以这种方式考虑,您可以说标准保留此类词语的方式几乎是保留此类词语的唯一方式。