何时使用下划线

在介绍C++变量命名规则时,我们提到在进行变量命名时:不能以数字开头,必须以 字母 (大小写不限)或 下划线 开头。而在使用下划线开头进行变量命名时,依然有一些规则需要遵循,如果使用了不规则的标识符,后果是不确定的。只是要注意,对这些规则的无知并不一定意味着代码不会编译或运行,但你写的代码很可能无法移植到不同的编译器和版本,因为不能保证不会有名称冲突。

C++编程下划线命名规则

  • 在任何范围内保留:

    • 下划线开头的标识符后跟大写字母,如_MyFoo

    • 包含双下划线的标识符,如__init、init__。

  • 保留在全局命名空间(global namespace)中

    • 下划线开头的标识符

  • std命名空间中的所有内容都是保留的,如cout、cin。


对下划线使用规则的总结就是可以使用单个下划线作为成员变量前缀,只要它后跟一个小写字母即可。但即使如此这依然有可能与当前或将来的保留标识符发生冲突。

因此,对于下划线,我们建议不要在任何地方使用双下划线,也最好不要命名以下划线开头的变量,以此来避免与编译器/操作系统/标准库发生冲突。

C++保留字规则

以下文本摘自C++保留字规则标准

7.1.3 保留标识符

(保留字包括)每个头声明或定义在其相关子句中列出的所有标识符,并可选地声明或定义在其相关的未来库方向子句中列出的标识符,这些标识符始终保留用于任何用途或用作文件范围标识符。

  • 所有以下划线和大写字母或另一个下划线开头的标识符始终保留供任何使用。

  • 所有以下划线开头的标识符始终保留用作普通名称空间和标记名称空间中具有文件范围的标识符。

  • 如果包含了任何关联的头文件,则其中任何子句(包括未来的库方向)中的每个宏名称都保留供指定的使用;除非另有明确说明(见 7.1.4)。

  • 以下任何子句(包括未来的库方向)中具有外部链接的所有标识符始终保留用作具有外部链接的标识符。(与外部连接保留的标识符的列表包括errnomath_errhandlingsetjmp,和va_end。)

  • 如果任何头文件被关联了,在其中的任何子句(包括未来的库方向)中列出的具有文件范围的每个标识符都保留用作宏名称以及用作同一名称空间中具有文件范围的标识符。

不保留其他标识符。如果程序在保留标识符的上下文中声明或定义标识符(7.1.4 允许的情况除外),或将保留标识符定义为宏名称,则行为未定义。

如果程序删除(使用#undef)上面列出的第一组中标识符的任何宏定义,则行为未定义。

对于保留字的总结如下:如果程序中包含了某个头文件,则不应该将该头文件中定义的宏名用作其他目的。C++语言保留了以两个下划线或下划线和大写字母打头的名称,还将以单个下划线打头的名称保留用作全局变量。C++语言保留了在库头文件中被声明为外部链接性的名称。

其他可能的保留标识符

除了在C++语言层次存在需要规避的保留字,其他标准限制也可能适用于变量命名规则。比如POSIX标准就保留了很多可能出现在正常代码中的标识符。

关于POSIX(Protabl Operation System 可移植操作系统规范)标准,简单来说是为了解决不同操作系统内核间软件移植的问题。比如常用的Linux和Windows系统都要实现基本的POSIX标准,将两个系统中不同的API封装成相同的函数名,这样即使使用不同的系统内核调用,也只需要调用同样的函数名就可以实现功能。(更详细讲解可参考POSIX解决什么问题

因此,对于POSIX标准中规定的标识符,我们也需将其视为保留字。当然,虽然现在将这些名称用于自己的目的可能不会造成问题,但它们确实增加了与该标准的未来版本发生冲突的可能性。

以下是常见的POSXI标准

类型 作用
E大写开头的名称后跟数字或大写字母 用于附加错误代码名称
小写字母开头isto后跟小写字母 用于额外的字符测试和转换功能。
LC_开头后跟一个大写字母 用于指定语言环境属性的附加宏。
fl为 后缀的所有现有数学函数的名称 分别对 float 和 long double 参数进行操作的相应函数
SIGSIG_后跟以大写字母开头的名称 用于额外的信号操作
str,memwcs开头后跟小写字母的名称 用于额外的字符串和数组函数
以任何小写字母开头PRISCN后跟或X 用于其他格式说明符宏
_t 结尾的名称 用于其他类型名称