在 C 标识符中使用下划线的规则是什么?

What are the rules about using an underscore in a C identifier?

在 C(和其他语言)中为变量和函数的名称使用前缀和后缀是很常见的。特别是,偶尔会看到在“适当的”标识符之前或之后使用下划线,例如_x_y 变量,或 _print 等。但是,还有避免名称以下划线开头的常识,以免与 C 标准库实现冲突。

那么,在什么地方、什么地方可以使用下划线呢?

足够好的经验法则

Don't start your identifier with an underscore.

就是这样。您可能仍然与某些特定于文件的定义有冲突(见下文),但这些只会给您一条错误消息,您可以自行处理。

安全,略有限制,经验法则

Don't start your identifier with:

  • An underscore.
  • Any 1-3 letter prefix, followed by an underscore, which isn't a proper word (e.g. a_, st_)
  • memory_ or atomic_.

and don't end your identifier with either _MIN or _MAX.

此规则涵盖的内容比实际保留的要多,但更容易记住。

更详细的规则

这是基于C2x standard draft (and thus covers previous standards' reservations) and the glibc documentation

不要使用:

  • 前缀__(两个下划线)。
  • 一个下划线后跟一个大写字母的前缀(例如 _D)。
  • 对于在文件范围内可见的标识符 - 前缀 _.
  • 以下带下划线的前缀,当后跟小写字母时:atomic_memory_memory_order_cnd_mtx_thrd_, tss_
  • 以下带下划线的前缀,后跟大写字符:LC_SIG_ATOMICTIME_
  • 后缀 _t(这是一个 POSIX 限制;对于 C 本身,您可以使用此后缀,除非您的标识符以 intuint 开头)

附加限制是每个库头文件而不是通用的(其中一些是 POSIX 限制):

If you use header file... You can't use identifiers with ...
dirent.h Prefix d_
fcntl.h Prefixes l_, F_, O_, and S_
grp.h Prefix gr_
limits.h Suffix _MAX (also probably _MIN)
pwd.h Prefix pw_
signal.h Prefixes sa_ and SA_
sys/stat.h Prefixes st_ and S_
sys/times.h Prefix tms_
termios.h Prefix 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.

— Each macro name in any of the following subclauses (including the future library directions) is reserved for use as specified if any of its associated headers is included; unless explicitly stated otherwise (see 7.1.4).
— All identifiers with external linkage in any of the following subclauses (including the future library directions) and errno are always reserved for use as identifiers with external linkage.184)
— Each identifier with file scope listed in any of the following subclauses (including the future library directions) is reserved for use as a macro name and as an identifier with file scope in the same name space if any of its associated headers is included.

其中“为任何用途保留”是指为 compiler/standard 库保留,请参阅 “为实施保留”也意味着为 compiler/standard 库保留。

此外,未来的库方向C17.31保留了很多标识符-这是一个很大的章节,我只引用最值得注意的部分:

7.31.10 Integer types <stdint.h> 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.

7.31.12 General utilities <stdlib.h>
Function names that begin with str and a lowercase letter may be added to the declarations in the <stdlib.h> header.

7.31.13 String handling <string.h>
Function names that begin with str, mem, or wcs and a lowercase letter may be added to the declarations in the <string.h> header.


直接回答你的问题:

So, where and where is it ok to use underscores?

严格来说:无处可去。你永远不应该声明以下划线开头的标识符,因为它们可能与标准库或语言关键字等冲突。尽管如上面粗体文本所暗示的那样,你可以在本地命名空间中使用一个下划线后跟一个小写字母。