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

c#(或者只是。net)似乎建议只使用下划线,就像在_foo中一样。c++标准允许这样做吗?


当前回答

避免名称冲突的规则既存在于c++标准中(参见Stroustrup书),也被c++大师(Sutter等)提到。

个人规则

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

当命名一个符号时,你可以避免与编译器/操作系统/标准库冲突,如果你:

永远不要以下划线开始符号 永远不要命名一个包含两个连续下划线的符号。

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

一些例子

(我使用宏是因为它们对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] 不以下划线开头的文字后缀标识符将保留以供将来标准化使用。

最后一个子句令人困惑,除非您认为一个以下划线开头,后面跟着一个小写字母的名称如果没有在全局命名空间中定义的话是可以的……

其他回答

是的,下划线可以在标识符中的任何地方使用。我认为规则是:第一个字符中的任何a-z, a-z, _和后面字符中的+0-9。

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

避免名称冲突的规则既存在于c++标准中(参见Stroustrup书),也被c++大师(Sutter等)提到。

个人规则

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

当命名一个符号时,你可以避免与编译器/操作系统/标准库冲突,如果你:

永远不要以下划线开始符号 永远不要命名一个包含两个连续下划线的符号。

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

一些例子

(我使用宏是因为它们对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] 不以下划线开头的文字后缀标识符将保留以供将来标准化使用。

最后一个子句令人困惑,除非您认为一个以下划线开头,后面跟着一个小写字母的名称如果没有在全局命名空间中定义的话是可以的……

从MSDN:

在标识符的开头使用两个连续的下划线字符(__),或者一个前导下划线后跟一个大写字母,这是为所有作用域的c++实现保留的。对于具有文件作用域的名称,应该避免使用一个前导下划线后面跟着一个小写字母,因为这可能与当前或未来的保留标识符冲突。

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

这显然是摘自c++标准的17.4.3.1.2节,但我在网上找不到完整标准的原始来源。

再看看这个问题。

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

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

从2003年c++标准:

17.4.3.1.2全局名称[lib.global.names] 某些名称和函数签名集总是保留给实现: 每个包含双下划线(__)或以下划线后跟大写字母(2.11)开头的名称将保留给实现,以供任何用途。 每个以下划线开头的名称都保留给实现,作为全局命名空间中的名称使用 165)这样的名称也保留在命名空间::std(17.4.3.1)中。

因为c++是基于C标准(1.1/2,c++ 03),而C99是一个规范参考(1.2/1,c++ 03),这些也适用于1999年的C标准:

7.1.3 Reserved identifiers Each header declares or defines all identifiers listed in its associated subclause, and optionally declares or defines identifiers listed in its associated future library directions subclause and identifiers which are always reserved either for any use or for use as file scope identifiers. 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) are always reserved for use as identifiers with external linkage.154 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. No other identifiers are reserved. If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), or defines a reserved identifier as a macro name, the behavior is undefined. If the program removes (with #undef) any macro definition of an identifier in the first group listed above, the behavior is undefined. 154) The list of reserved identifiers with external linkage includes errno, math_errhandling, setjmp, and va_end.

其他限制也可能适用。例如,POSIX标准保留了很多可能在正常代码中出现的标识符:

Names beginning with a capital E followed a digit or uppercase letter: may be used for additional error code names. Names that begin with either is or to followed by a lowercase letter may be used for additional character testing and conversion functions. Names that begin with LC_ followed by an uppercase letter may be used for additional macros specifying locale attributes. Names of all existing mathematics functions suffixed with f or l are reserved for corresponding functions that operate on float and long double arguments, respectively. Names that begin with SIG followed by an uppercase letter are reserved for additional signal names. Names that begin with SIG_ followed by an uppercase letter are reserved for additional signal actions. Names beginning with str, mem, or wcs followed by a lowercase letter are reserved for additional string and array functions. Names beginning with PRI or SCN followed by any lowercase letter or X are reserved for additional format specifier macros Names that end with _t are reserved for additional type names.

虽然现在为自己的目的使用这些名称可能不会引起问题,但它们确实增加了与该标准的未来版本发生冲突的可能性。


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

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

关于任何以_t结尾的标识符的规则让我非常惊讶。我认为这是POSIX标准(还不确定)寻求澄清和官方章节。这来自GNU libtool手册,列出了保留名称。

CesarB提供了以下POSIX 2004保留符号的链接,并指出“许多其他保留前缀和后缀……可以在那里找到。的 POSIX 2008保留符号定义在这里。这些限制在某种程度上比上述限制更加微妙。

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

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