协慌网

登录 贡献 社区

在 C ++ 标识符中使用下划线有哪些规则?

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

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

答案

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

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

从 2003 C ++ 标准:

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

某些名称和函数签名集始终保留给实现:

  • 每个包含双下划线( __ )或以下划线后跟大写字母(2.11)开头的名称都保留给实现以供任何使用。
  • 以下划线开头的每个名称都保留给实现,以用作全局名称空间中的名称。 165

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 保留标识符

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

  • 所有以下划线开头的标识符以及大写字母或另一个下划线始终保留用于任何用途。
  • 所有以下划线开头的标识符始终保留用作普通和标记名称空间中具有文件范围的标识符。
  • 如果包含任何相关标头,则保留以下任何子条款中的每个宏名称(包括未来的库方向)以供指定使用; 除非另有明确说明(见 7.1.4)。
  • 所有以下子条款中包含外部链接的标识符(包括未来的库方向)始终保留用作具有外部链接的标识符。 154
  • 在以下任何子条款中列出的具有文件范围的每个标识符(包括未来的库方向)保留用作宏名称,并且如果包括任何相关联的标题,则用作具有相同名称空间的文件范围的标识符。

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

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

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

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

  • 以大写字母E开头的名称后跟一个数字或大写字母:
    • 可用于其他错误代码名称。
  • 与任一开始的名字isto后跟一个小写字母
    • 可用于其他字符测试和转换功能。
  • LC_开头,后跟大写字母的名称
    • 可用于指定区域设置属性的其他宏。
  • 保留以fl为后缀的所有现有数学函数的名称
    • 对于分别对 float 和 long double 参数进行操作的相应函数。
  • SIG开头后跟大写字母的名称将被保留
    • 用于其他信号名称。
  • SIG_开头,后跟大写字母的名称将被保留
    • 用于其他信号动作。
  • strmemwcs开头,后跟小写字母的名称将被保留
    • 用于其他字符串和数组函数。
  • PRISCN开头,后跟任何小写字母或X被保留
    • 用于其他格式说明符宏
  • _t结尾的名称是保留的
    • 用于其他类型名称。

虽然现在将这些名称用于您自己的目的可能不会导致问题,但它们确实会增加与该标准的未来版本冲突的可能性。


就个人而言,我只是不用下划线开始标识符。我的规则的新增内容:不要在任何地方使用双下划线,这很容易,因为我很少使用下划线。

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

任何以_t结尾的标识符的规则都让我感到惊讶。我认为这是一个 POSIX 标准(尚不确定)寻找澄清和官方章节和经文。这来自GNU libtool 手册 ,列出了保留名称。

CesarB 提供了以下指向POSIX 2004保留符号的链接,并注意到 “可以在那里找到许多其他保留的前缀和后缀......”。 POSIX 2008保留符号在此处定义。这些限制比上述限制更微妙。

避免名称冲突的规则都是 C ++ 标准(参见 Stroustrup 书)和 C ++ 大师(Sutter 等)提到的。

个人规则

因为我不想处理案件,并且想要一个简单的规则,我设计了一个简单而正确的个人案例:

命名符号时,如果您符合以下条件,则可避免与编译器 / OS / 标准库冲突:

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

当然,将代码放在一个唯一的命名空间中也有助于避免冲突(但不能防止恶意宏)

一些例子

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

#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 ++ 实现保留单个前导下划线后跟大写字母。对于具有文件范围的名称,应避免使用一个前导下划线后跟小写字母,因为可能与当前或将来的保留标识符冲突。

这意味着您可以使用单个下划线作为成员变量前缀,只要它后面跟一个小写字母。

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

另见这个问题