"reserved for any use" 是什么意思?
What's the meaning of "reserved for any use"?
注意:这是 c question, though I added c++ 以防某些 C++ 专家可以提供 C++ 使用与 C 不同的措辞的基本原理或历史原因。
在C标准库规范中,我们有这个规范文本,C17 7.1.3保留标识符(强调我的):
- 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.
现在我一直在阅读各种受人尊敬的 C 专家对 SO 的回答,他们声称编译器或标准库可以使用带有下划线 + 大写字母或双下划线的标识符。
难道 "reserved for any use" 不意味着保留给 任何人 除了 C 语言本身的未来扩展吗?这意味着实施 不允许 使用它们。
虽然上面的第二个短语,关于单前导下划线似乎是针对实现的?
一般来说,C 标准的编写方式期望编译器 vendors/library 实现者是典型的 reader - 而不是应用程序程序员。
值得注意的是,C++ 的措辞非常不同:
- Each name that contains a double underscore (
__
) or begins with an underscore followed by an uppercase letter (2.11) is reserved to the implementation for any use.
(见What are the rules about using an underscore in a C++ identifier?)
这可能是 C 和 C++ 之间的混淆,这里的语言不同吗?
在 C 标准中,术语 "reserved" 的含义由 7.1.3p2 定义,紧接在您引用的项目符号列表下方:
No other identifiers are reserved. If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.
强调我的:保留的标识符对 程序 施加了限制,而不是实现。因此,常见的解释——保留的标识符可以被实现用于任何目的——对 C 来说是正确的。
我没有跟上C++标准,觉得没有资格解释它了。
虽然该标准主要是为了指导实施者而编写的,但它 是作为 描述什么使程序格式正确及其效果是什么的描述。这是因为符合标准的编译器的基本 定义 是为任何符合标准的程序做正确事情的编译器:
A strictly conforming program shall use only those features of the language and library
specified in this International Standard....A conforming
hosted implementation shall accept any strictly conforming program.
单独阅读,这极大地限制了编译器的扩展。例如,仅基于该子句,编译器不应该定义 any 自己的保留字。毕竟,特定编译器可能 想要 保留的任何给定单词仍然可以出现在严格符合的程序中,迫使编译器的手。
标准继续进行,但是:
A conforming implementation may have extensions (including additional
library functions), provided they do not alter the behavior of any strictly conforming
program.
这是关键部分。编译器扩展需要以影响 不合格 程序(包含未定义行为,或者根本不应该编译的程序)的方式编写,允许它们编译并获得乐趣额外的东西。
所以定义 "reserved identifiers" 的目的是,当语言实际上 不需要 任何东西的那些标识符时,通过提供它们来给实现一些额外的回旋余地有些事情会使程序不合格。编译器之所以可以将 __declspec
识别为声明的一部分,是因为将 __declspec
放入声明中是非法的,因此编译器可以为所欲为!
因此,"reserved for any use" 的重要性在于,它毫无疑问地表明编译器有能力将此类标识符视为具有它所关心的任何含义。未来的兼容性是一个相对遥远的问题。
C++ 标准以类似的方式工作,但它的策略更明确一些:
A conforming implementation may have extensions (including additional library functions), provided they do
not alter the behavior of any well-formed program. Implementations are required to diagnose programs that
use such extensions that are ill-formed according to this International Standard. Having done so, however,
they can compile and execute such programs.
我怀疑措辞上的差异归结于 C++ 标准,只是更清楚地说明了扩展是如何工作的。尽管如此,C 标准中的任何内容都不会阻止实现执行相同的操作。 (而且我们基本上都忽略了每次使用__declspec
时编译器都会警告你的要求。)
关于C和C++在措辞上的差异,我把自己的小研究贴在这里作为参考:
早期K&R C 1st edition有这段文字:
...names which are intended for use only by functions of the library begin with an underscore so they are less likely to collide with names in a user's program.
K&R 第 2 版添加了一个附录 B,其中介绍了标准库,我们可以在其中阅读
External identifiers that begin with an underscore are reserved for use by the library, as are all
other identifiers that begin with an underscore and an upper-case letter or another underscore.
早期的 ANSI C 草案以及 "C90" ISO 9899:1990 与当前 ISO 标准中的文本相同。
不过,正如@hvd 所指出的,最早的 C++ 草案有一个不同的文本,可能是对 C 标准的澄清。来自 DRAFT: 20 September 1994:
17.3.3.1.2 Global names
...
Each name that begins with an underscore and either an uppercase letter or another underscore (2.8) is
reserved to the implementation for any use
显然 "reserved for any use" 这个措辞是由 ANSI/ISO C90 委员会发明的,而几年后 C++ 委员会使用了更清晰的措辞,类似于准标准 K&R 书中的措辞。
C99 基本原理 V5.10 在 7.1.3 下面这样说:
Also reserved for the implementor are all external identifiers beginning with an underscore, and
all other identifiers beginning with an underscore followed by a capital letter or an underscore.
This gives a name space for writing the numerous behind-the-scenes non-external macros and
functions a library needs to do its job properly.
这使得委员会的意图非常明确:"reserved for any use" 表示 "reserved for the implementor"。
还要注意,当前的 C 标准在 6.2.5 的其他地方有以下规范文本:
There may also be
implementation-defined extended signed integer types. 38)
信息脚注 38 说:
38) Implementation-defined keywords shall have the form of an identifier reserved for any use as
described in 7.1.3.
C 有多个上下文,其中一个符号可以有一个定义:
- 宏名space,
- 宏参数的正式名称space(此space特定于每个类函数宏),
- 普通标识符的space,
- 标签名称space,
- 标签的space(这个space是每个函数所特有的),
- structure/union 个成员中的 space 个(这个 space 每个 struct/union 是特定的)。
什么 "reserved for any use" 表示兼容程序中的用户代码不能使用1 以下划线开头,后跟大写字母或另一个下划线的符号任何上述情况。与以单个下划线开头但后跟小写数字或数字的标识符进行比较。这属于以下划线开头的第二个 class 标识符。用户代码 可以 可以将这些标识符用作宏参数的名称、标签或 structure/union 成员的名称。
"Reserved for any use" 并不意味着实现不能使用此类符号。保留的目的是提供一个名称 space 实现可以自由使用,而不用担心实现定义的名称将与兼容程序中的用户代码定义的名称冲突。
1标准并不完全是"cannot use"的意思。该标准鼓励以编程方式使用少量以双下划线开头的名称。例如,需要一个兼容的实现来定义 __STDC_VERSION__
、__FILE__
、__LINE__
和 __func__
。该标准的 2011 版本甚至给出了一个可能引用 __func__
的合规程序示例。
C 标准允许实现附加他们认为适合保留标识符的任何含义。当没有理由不这样做时,大多数实现会将保留形式的无法识别的标识符与任何其他已识别的标识符一样对待,因此允许类似:
#ifdef __ACME_COMPILER
#define near __near
#else
#define near
#endif
int near foo;
如果代码正在 Acme 编译器中处理(可能会支持这样的事情),则使用 __near
限定符声明标识符 foo
,但也与其他编译器兼容不需要或受益于使用这样的指令。没有什么可以禁止符合规范的实现定义 __ACME_COMPILER
并将 __near
解释为 "launch nuclear missiles",但是高质量的实现不应该像上面那样破坏代码。如果一个实现不知道 __ACME_COMPILER
应该是什么意思,那么像对待任何其他未知标识符一样对待它会允许它支持像上面这样的有用结构。
已经晚了几个月,但还有一点尚未解决。
你的问题可以从相反的方向来看。该标准允许实现(正如您所观察到的)使用像 _Foo
这样的符号,但更重要的是,因此禁止实现使用 foo
。后者保留供您使用。
为了便于理解,假设未来的 C 标准引入了新关键字 _Foo
。假设的实现已经在使用这个符号,那么会发生什么?
答案:
首先,执行时还没有执行新标准。新标准尚未实施,缺乏实际效果。
后来,作为实施新标准的一部分,实施悄悄地将每个 _Foo
更改为 _Bar
。
没问题。
事实上,如果你这样想,可以说标准保留这些词的方式几乎是唯一可以保留它们的方式。
注意:这是 c question, though I added c++ 以防某些 C++ 专家可以提供 C++ 使用与 C 不同的措辞的基本原理或历史原因。
在C标准库规范中,我们有这个规范文本,C17 7.1.3保留标识符(强调我的):
- 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.
现在我一直在阅读各种受人尊敬的 C 专家对 SO 的回答,他们声称编译器或标准库可以使用带有下划线 + 大写字母或双下划线的标识符。
难道 "reserved for any use" 不意味着保留给 任何人 除了 C 语言本身的未来扩展吗?这意味着实施 不允许 使用它们。
虽然上面的第二个短语,关于单前导下划线似乎是针对实现的?
一般来说,C 标准的编写方式期望编译器 vendors/library 实现者是典型的 reader - 而不是应用程序程序员。
值得注意的是,C++ 的措辞非常不同:
- Each name that contains a double underscore (
__
) or begins with an underscore followed by an uppercase letter (2.11) is reserved to the implementation for any use.
(见What are the rules about using an underscore in a C++ identifier?)
这可能是 C 和 C++ 之间的混淆,这里的语言不同吗?
在 C 标准中,术语 "reserved" 的含义由 7.1.3p2 定义,紧接在您引用的项目符号列表下方:
No other identifiers are reserved. If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined.
强调我的:保留的标识符对 程序 施加了限制,而不是实现。因此,常见的解释——保留的标识符可以被实现用于任何目的——对 C 来说是正确的。
我没有跟上C++标准,觉得没有资格解释它了。
虽然该标准主要是为了指导实施者而编写的,但它 是作为 描述什么使程序格式正确及其效果是什么的描述。这是因为符合标准的编译器的基本 定义 是为任何符合标准的程序做正确事情的编译器:
A strictly conforming program shall use only those features of the language and library specified in this International Standard....A conforming hosted implementation shall accept any strictly conforming program.
单独阅读,这极大地限制了编译器的扩展。例如,仅基于该子句,编译器不应该定义 any 自己的保留字。毕竟,特定编译器可能 想要 保留的任何给定单词仍然可以出现在严格符合的程序中,迫使编译器的手。
标准继续进行,但是:
A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any strictly conforming program.
这是关键部分。编译器扩展需要以影响 不合格 程序(包含未定义行为,或者根本不应该编译的程序)的方式编写,允许它们编译并获得乐趣额外的东西。
所以定义 "reserved identifiers" 的目的是,当语言实际上 不需要 任何东西的那些标识符时,通过提供它们来给实现一些额外的回旋余地有些事情会使程序不合格。编译器之所以可以将 __declspec
识别为声明的一部分,是因为将 __declspec
放入声明中是非法的,因此编译器可以为所欲为!
因此,"reserved for any use" 的重要性在于,它毫无疑问地表明编译器有能力将此类标识符视为具有它所关心的任何含义。未来的兼容性是一个相对遥远的问题。
C++ 标准以类似的方式工作,但它的策略更明确一些:
A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any well-formed program. Implementations are required to diagnose programs that use such extensions that are ill-formed according to this International Standard. Having done so, however, they can compile and execute such programs.
我怀疑措辞上的差异归结于 C++ 标准,只是更清楚地说明了扩展是如何工作的。尽管如此,C 标准中的任何内容都不会阻止实现执行相同的操作。 (而且我们基本上都忽略了每次使用__declspec
时编译器都会警告你的要求。)
关于C和C++在措辞上的差异,我把自己的小研究贴在这里作为参考:
早期K&R C 1st edition有这段文字:
...names which are intended for use only by functions of the library begin with an underscore so they are less likely to collide with names in a user's program.
K&R 第 2 版添加了一个附录 B,其中介绍了标准库,我们可以在其中阅读
External identifiers that begin with an underscore are reserved for use by the library, as are all other identifiers that begin with an underscore and an upper-case letter or another underscore.
早期的 ANSI C 草案以及 "C90" ISO 9899:1990 与当前 ISO 标准中的文本相同。
不过,正如@hvd 所指出的,最早的 C++ 草案有一个不同的文本,可能是对 C 标准的澄清。来自 DRAFT: 20 September 1994:
17.3.3.1.2 Global names
...
Each name that begins with an underscore and either an uppercase letter or another underscore (2.8) is reserved to the implementation for any use
显然 "reserved for any use" 这个措辞是由 ANSI/ISO C90 委员会发明的,而几年后 C++ 委员会使用了更清晰的措辞,类似于准标准 K&R 书中的措辞。
C99 基本原理 V5.10 在 7.1.3 下面这样说:
Also reserved for the implementor are all external identifiers beginning with an underscore, and all other identifiers beginning with an underscore followed by a capital letter or an underscore. This gives a name space for writing the numerous behind-the-scenes non-external macros and functions a library needs to do its job properly.
这使得委员会的意图非常明确:"reserved for any use" 表示 "reserved for the implementor"。
还要注意,当前的 C 标准在 6.2.5 的其他地方有以下规范文本:
There may also be implementation-defined extended signed integer types. 38)
信息脚注 38 说:
38) Implementation-defined keywords shall have the form of an identifier reserved for any use as described in 7.1.3.
C 有多个上下文,其中一个符号可以有一个定义:
- 宏名space,
- 宏参数的正式名称space(此space特定于每个类函数宏),
- 普通标识符的space,
- 标签名称space,
- 标签的space(这个space是每个函数所特有的),
- structure/union 个成员中的 space 个(这个 space 每个 struct/union 是特定的)。
什么 "reserved for any use" 表示兼容程序中的用户代码不能使用1 以下划线开头,后跟大写字母或另一个下划线的符号任何上述情况。与以单个下划线开头但后跟小写数字或数字的标识符进行比较。这属于以下划线开头的第二个 class 标识符。用户代码 可以 可以将这些标识符用作宏参数的名称、标签或 structure/union 成员的名称。
"Reserved for any use" 并不意味着实现不能使用此类符号。保留的目的是提供一个名称 space 实现可以自由使用,而不用担心实现定义的名称将与兼容程序中的用户代码定义的名称冲突。
1标准并不完全是"cannot use"的意思。该标准鼓励以编程方式使用少量以双下划线开头的名称。例如,需要一个兼容的实现来定义 __STDC_VERSION__
、__FILE__
、__LINE__
和 __func__
。该标准的 2011 版本甚至给出了一个可能引用 __func__
的合规程序示例。
C 标准允许实现附加他们认为适合保留标识符的任何含义。当没有理由不这样做时,大多数实现会将保留形式的无法识别的标识符与任何其他已识别的标识符一样对待,因此允许类似:
#ifdef __ACME_COMPILER
#define near __near
#else
#define near
#endif
int near foo;
如果代码正在 Acme 编译器中处理(可能会支持这样的事情),则使用 __near
限定符声明标识符 foo
,但也与其他编译器兼容不需要或受益于使用这样的指令。没有什么可以禁止符合规范的实现定义 __ACME_COMPILER
并将 __near
解释为 "launch nuclear missiles",但是高质量的实现不应该像上面那样破坏代码。如果一个实现不知道 __ACME_COMPILER
应该是什么意思,那么像对待任何其他未知标识符一样对待它会允许它支持像上面这样的有用结构。
已经晚了几个月,但还有一点尚未解决。
你的问题可以从相反的方向来看。该标准允许实现(正如您所观察到的)使用像 _Foo
这样的符号,但更重要的是,因此禁止实现使用 foo
。后者保留供您使用。
为了便于理解,假设未来的 C 标准引入了新关键字 _Foo
。假设的实现已经在使用这个符号,那么会发生什么?
答案:
首先,执行时还没有执行新标准。新标准尚未实施,缺乏实际效果。
后来,作为实施新标准的一部分,实施悄悄地将每个
_Foo
更改为_Bar
。
没问题。
事实上,如果你这样想,可以说标准保留这些词的方式几乎是唯一可以保留它们的方式。