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


930

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

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



6
只是要注意,对这些规则的无知并不一定意味着您的代码将无法编译或运行,但是您的代码很可能无法移植到不同的编译器和版本,因为不能保证不会有名称。冲突。为了支持这一点,我知道某个重要系统的某些实现,该系统一直在各处使用_大写字母作为命名约定。那里没有任何错误。当然,这是不好的做法。
g24l

Answers:


851

规则(在C ++ 11中未更改):

  • 在任何范围内都保留,包括用作实现宏:
    • 以下划线开头的标识符,紧随其后的是大写字母
    • 包含相邻下划线(或“双下划线”)的标识符
  • 在全局名称空间中保留:
    • 下划线开头的标识符
  • 同样,std名称空间中的所有内容均保留。(不过,您可以添加模板专长。)

根据2003 C ++标准:

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

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

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

165)这样的名称也在名称空间::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_errhandlingsetjmp,和va_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保留符号在这里被定义。这些限制比上述限制更加细微。


14
C ++标准不会“导入” C语言,对吗?据我所知,它们导入某些标头,但不导入整个语言或命名规则。但是,是的,也让我感到惊讶。但是由于它是C,所以只能应用于全局ns。在我读课时可以安全地在类中使用_t
jalf

27
C ++标准不会“导入” C标准。它引用了C标准。C ++库介绍说:“该库还提供了标准C库的功能”。它通过在C标准库的标头中进行适当的更改来做到这一点,而不是通过“导入”它来实现。C ++标准具有一组描述保留名称的规则。如果在C中保留的名称应该在C ++中保留,那就可以这样说。但是C ++标准却没有这样说。所以我不相信C保留的东西是C ++保留的-但我很可能错了。
约翰尼斯·绍布

8
这是我发现的有关“ _t”问题的内容:n1256(C99 TC3)说:“保留以int或uint开头并以_t结尾的Typedef名称”。我认为仍然允许使用“ foo_t”之类的名称-但我认为这些名称随后由POSIX保留。
Johannes Schaub-litb

59
那么POSIX保留了“ tolerance”,因为它以“ to” +小写字母开头?我敢打赌,很多代码都违反了这个规则!
Sjoerd

23
@LokiAstari,“ C ++标准是根据C标准定义的。基本上,它说C ++是具有这些差异和补充的C。 ”废话!C ++仅在[basic.fundamental]和库中引用了C标准。如果您说的是正确的,那么C ++会在哪说,_Bool_ImaginaryC ++中不存在?C ++语言是明确定义的,而不是对C的“编辑”,否则标准可能要短得多!
乔纳森·威克里

197

避免名称冲突的规则既在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]

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

最后一个子句令人困惑,除非您认为如果在全局名称空间中定义,则以一个下划线开头并以小写字母开头的名称是可以的。


9
@Meysam:__WRONG_AGAIN__包含两个连续的下划线(开头两个,结尾两个),因此按照标准,这是错误的。
paercebal 2012年

8
@BЈовић:WRONG__WRONG包含两个连续的下划线(中间两个),所以按照标准,这是错误的
paercebal 2013年

2
将代码放在唯一的命名空间中也有助于避免冲突:但是,这还不够,因为标识符可能会与关键字发生冲突,而与范围无关(例如,__attribute__对于GCC)。
Ruslan'9

1
为什么按照标准在中间有两个连续的下划线会有任何问题?用户定义的文字后缀适用于诸如1234567L或的文字值4.0f。IIRC指的是ohttp://en.cppreference.com/w/cpp/language/user_literal
Jason S

1
Why is there any problem of having two consecutive underscores in the middle according to the standard?因为标准说那些是保留的。这不是关于好坏的建议。这是标准的决定。他们为什么决定这个?我想第一批编译器在标准化之前就已经非正式地使用过这些约定。
paercebal

38

MSDN

在所有范围内,C ++实现均保留在标识符的开头使用两个连续的下划线字符(__)或使用单个下划线后跟一个大写字母。对于具有文件范围的名称,应避免使用前导下划线后跟小写字母,因为这可能与当前或将来的保留标识符冲突。

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

这显然取自C ++标准的17.4.3.1.2节,但是我找不到在线完整标准的原始资料。

另请参阅此问题


2
我在n3092.pdf(C ++ 0x标准草案)的以下部分中找到了类似的文本:“ 17.6.3.3.2全局名称”
paercebal 2011年

7
有趣的是,这似乎是对该问题有直接,简洁答案的唯一答案。
海德2014年

9
@hyde:实际上不是,因为它跳过了规则,即在全局命名空间中不包含任何带有前划线的标识符。参见Roger的答案。我会非常谨慎地引用MS VC文档作为C ++标准的权威。
2015年

@sbi我指的 是此答案中的“您可以使用单个下划线作为成员变量前缀,只要其后跟一个小写字母”即可直接简洁地回答问题文本中的问题,而不会被淹没在墙上的文字。
海德

5
首先,我仍然认为缺少任何提示,即同一规则不适用于全局名称空间是失败的。但是,更糟糕的是,不仅在标识符的开头而且在标识符的任何地方都禁止相邻的下划线。因此,这个答案不仅是忽略了一个事实,而且实际上至少提出了一个错误的主张。就像我说的那样,除非问题仅与VC有关,否则我不会引用MSVC文档。
2015年

25

至于问题的另一部分,通常将下划线放在变量名的末尾,以免与内部任何内容发生冲突。

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


2

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

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


3
它们在库中很常见。它们在用户代码中不应通用。
马丁·约克

43
人们用C写库,你知道的。
约翰·米利金

7
“是的,下划线可以在标识符的任何地方使用。” 对于全局标识符,这是错误的。参见Roger的答案
2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.