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

在C ++中通常使用某种前缀命名成员variables,以表示它们是成员variables,而不是局部variables或参数。 如果你来自MFC背景,你可能会使用m_foo 。 偶尔也看过myFoo

C#(或可能只是.NET)似乎build议只使用下划线,如_foo 。 这是由C ++标准允许的吗?

规则(在C ++ 11中没有改变):

  • 保留在任何范围内,包括用作实现macros:
    • 标识符以下划线开头,后面紧跟着一个大写字母
    • 包含相邻下划线(或“双下划线”)的标识符
  • 保留在全局名称空间中:
    • 以下划线开头的标识符
  • 而且, std命名空间中的所有内容都是保留的。 (尽pipe你可以添加模板专业化。)

从2003年的C ++标准:

17.4.3.1.2全局名称[lib.global.names]

某些名称和函数签名集总是保留给实现:

  • 每个包含双下划线(_ _)的名称或以下划线开头,后面跟着一个大写字母(2.11)的字符将保留给实施用于任何用途。
  • 每个以下划线开头的名字都保留给实现,用作全局名称空间中的名称。 165

这些名字也保留在namespace :: std(17.4.3.1)中。

因为C ++是基于C标准(1.1 / 2,C ++ 03)而C99是规范性参考(1.2 / 1,C ++ 03),所以这些也适用于1999 C标准:

7.1.3保留的标识符

每个头部声明或定义在其相关的子条款中列出的所有标识符,并且可选地声明或定义在其相关联的未来库方向子条款中列出的标识符和总是被保留用于任何用途或用作文件范围标识符的标识符。

  • 所有以下划线和大写字母或其他下划线开头的标识符总是保留用于任何用途。
  • 以下划线开始的所有标识符总是被保留用作普通标签和标签名称空间中具有文件范围的标识符。
  • 如果包含任何相关标题,则下列任何子条款(包括未来的图书馆方向)中的每个macros名称都被保留以供指定使用; 除非另有明确说明(见7.1.4)。
  • 任何下列小节(包括未来图书馆方向)中的所有具有外部链接的标识符总是保留用作具有外部链接的标识符。 154
  • 每个包含以下任何子条款(包括未来库指令)的文件范围的标识符都被保留作为macros名称,并且如果包含任何相关头文件,则将其作为文件范围在相同名称空间中的标识符。

没有其他标识符被保留。 如果程序在保留的上下文中声明或定义了一个标识符(7.1.4中允许的除外),或者将一个保留的标识符定义为macros名称,则行为是不确定的。

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

154)带有外部链接的保留标识符列表包括errnomath_errhandlingsetjmpva_end

其他限制可能适用。 例如,POSIX标准保留了很多可能以正常代码显示的标识符:

  • 以大写字母“E”开头的名字后跟一个数字或大写字母:
    • 可能会用于其他错误代码名称。
  • 名称以“是”或“to”开头,后跟小写字母
    • 可用于附加的字符testing和转换function。
  • 名称以“LC_”开头,后跟大写字母
    • 可用于指定语言环境属性的其他macros。
  • 保留所有现有math函数的后缀名为“f”或“l”
    • 用于分别对float和long double参数进行操作的相应函数。
  • 以“SIG”开头的名称后面跟着一个大写字母
    • 为额外的信号名称。
  • 以“SIG_”开头并以大写字母开头的名称将被保留
    • 用于附加的信号动作。
  • 以“str”,“mem”或“wcs”开头的名字后面跟着一个小写字母
    • 用于附加的string和数组函数。
  • 名称以“PRI”或“SCN”开头,后面跟着小写字母或“X”
    • 为额外的格式说明符macros
  • 以'_t'结尾的名字是保留的
    • 为额外的types名称。

尽pipe目前将这些名称用于自己的目的可能不会造成问题,但它们确实会提高与未来版本的标准冲突的可能性。


就个人而言,我不会用下划线来启动标识符。 我的规则的新增加:不要在任何地方使用双下划线,这很容易,因为我很less使用下划线。

在对本文进行研究之后,我不再用'_t'来结束我的标识符,因为这是POSIX标准保留的。

关于以'_t'结尾的任何标识符的规则都让我感到惊讶。 我认为这是一个POSIX标准(还不确定)寻求澄清和官方章节和诗句。 这是从GNU libtool手册,列出保留的名称。

CesarB提供了以下链接到POSIX 2004保留的符号,并指出“许多其他保留的前缀和后缀…可以在那里find”。 这里定义了POSIX 2008保留的符号。 这些限制比上面的限制更为细微。

避免名称冲突的规则都在C ++标准中(参见Stroustrup书),并由C ++大师(Sutter等)提及。

个人规则

因为我不想处理案件,想要一个简单的规则,我devise了一个既简单又正确的私人案例:

命名符号时,如果您符合以下条件,您将避免与编译器/操作系统/标准库冲突:

  • 永远不要用下划线开始一个符号
  • 永远不要用两个连续的下划线来命名符号。

当然,把你的代码放在一个唯一的名字空间中也有助于避免碰撞(但是不能防止邪恶的macros)

一些例子

(我使用macros是因为它们是C / C ++符号的更多代码污染,但是它可以是从variables名到类名的任何东西)

 #define _WRONG #define __WRONG_AGAIN #define RIGHT_ #define WRONG__WRONG #define RIGHT_RIGHT #define RIGHT_x_RIGHT 

从C ++ 0x草案中提取

从n3242.pdf文件(我期望最终的标准文本是相似的):

17.6.3.3.2全局名称[global.names]

某些名称和函数签名集总是保留给实现:

– 包含双下划线_ _的每个名称或以下划线开头,后面跟着大写字母(2.12)的内容保留给实施用于任何用途。

– 以下划线开头的每个名称都保留给实现,以用作全局名称空间中的名称。

但也:

17.6.3.3.5用户定义的文字后缀[usrlit.suffix]

不以下划线开头的文字后缀标识符被保留用于将来的标准化。

这最后一个条款是令人困惑的,除非你认为一个名字以一个下划线开头,后面跟一个小写字母,如果没有在全局名字空间中定义,那么这个名字是OK的。

来自MSDN :

在标识符的开始处使用两个连续的下划线字符(__),或者使用单引号下划线后跟一个大写字母,在所有作用域中都用于C ++实现。 由于可能与当前或将来的保留标识符冲突,因此应避免使用一个带有文件范围名称的前导下划线,后跟一个小写字母。

这意味着你可以使用一个下划线作为成员variables前缀,只要后面跟着一个小写字母即可。

这显然取自C ++标准的第17.4.3.1.2节,但我无法find在线完整标准的原始来源。

另见这个问题 。

至于问题的另一部分,通常把下划线放在variables名的末尾 ,以免与内部任何东西发生冲突。

我甚至在类和名字空间内部这样做,因为我只需要记住一条规则(与“在全局范围内的名称末尾和其他地方的名称的开头”相比较)。

是的,下划线可以在标识符的任何地方使用。 我相信这些规则是:第一个字符中的az,AZ,以及后面的字符都是+ 0-9。

下划线前缀在C代码中很常见 – 单个下划线表示“私有”,双下划线通常保留供编译器使用。