在C ++中,通常使用某种前缀来命名成员变量,以表示它们是成员变量,而不是局部变量或参数。如果您是来自MFC的背景,则可能会使用m_foo
。我也myFoo
偶尔见过。
C#(或可能只是.NET)似乎建议仅使用下划线,如中所示_foo
。C ++标准允许吗?
在C ++中,通常使用某种前缀来命名成员变量,以表示它们是成员变量,而不是局部变量或参数。如果您是来自MFC的背景,则可能会使用m_foo
。我也myFoo
偶尔见过。
C#(或可能只是.NET)似乎建议仅使用下划线,如中所示_foo
。C ++标准允许吗?
Answers:
规则(在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)与外部连接保留的标识符的列表包括
errno
,math_errhandling
,setjmp
,和va_end
。
其他限制可能适用。例如,POSIX标准保留了很多可能以普通代码显示的标识符:
E
大写字母开头,后跟数字或大写字母:
is
或to
之后的
名称LC_
后跟一个大写字母
f
或l
保留
SIG
保留以大写字母
开头的名称SIG_
保留以大写字母
开头的名称str
,mem
或wcs
后跟小写字母的名称
PRI
或SCN
后跟,或X
保留
_t
被保留
尽管现在将这些名称用于您自己的目的可能不会引起问题,但它们确实增加了与该标准的未来版本冲突的可能性。
我个人只是不以下划线开头标识符。我的规则的新增内容:不要在任何地方使用双下划线,这很容易,因为我很少使用下划线。
在对本文进行了研究之后,我不再以标识符结尾,_t
因为这是POSIX标准保留的。
关于以标识符结尾的标识符的规则_t
令我非常惊讶。我认为这是POSIX标准(尚不确定),需要澄清和官方章节。这来自GNU libtool手册,其中列出了保留名称。
CesarB提供了指向POSIX 2004保留符号的以下链接,并指出“在此可以找到许多其他保留的前缀和后缀...”。该 POSIX 2008保留符号在这里被定义。这些限制比上述限制更加细微。
_Bool
而_Imaginary
C ++中不存在?C ++语言是明确定义的,而不是对C的“编辑”,否则标准可能要短得多!
避免名称冲突的规则既在C ++标准中(请参阅Stroustrup书),也在C ++专家中提到(Sutter等)。
因为我不想处理案件,而是想要一个简单的规则,所以我设计了一个既简单又正确的个人规则:
在命名符号时,如果满足以下条件,将避免与编译器/ OS /标准库冲突:
当然,将代码放在唯一的命名空间中也有助于避免冲突(但不能防止邪恶的宏)
(我使用宏是因为它们是C / C ++符号的更多代码污染,但是它可以是从变量名到类名的任何东西)
#define _WRONG
#define __WRONG_AGAIN
#define RIGHT_
#define WRONG__WRONG
#define RIGHT_RIGHT
#define RIGHT_x_RIGHT
从n3242.pdf文件中(我希望最终的标准文本类似):
17.6.3.3.2全局名称[global.names]
某些名称和函数签名集始终保留给实现:
—每个包含双下划线_ _或以下划线后跟大写字母(2.12)开头的名称都保留给实现以供任何使用。
—每个以下划线开头的名称都保留给实现,以用作全局名称空间中的名称。
但是也:
17.6.3.3.5用户定义的文字后缀[usrlit.suffix]
不以下划线开头的文字后缀标识符将保留,以供将来标准化。
最后一个子句令人困惑,除非您认为如果未在全局名称空间中定义,则以一个下划线开头并以小写字母开头的名称是可以的。
__WRONG_AGAIN__
包含两个连续的下划线(开头两个,结尾两个),因此按照标准,这是错误的。
WRONG__WRONG
包含两个连续的下划线(中间两个),所以按照标准,这是错误的
__attribute__
对于GCC)。
1234567L
或的文字值4.0f
。IIRC指的是ohttp://en.cppreference.com/w/cpp/language/user_literal
Why is there any problem of having two consecutive underscores in the middle according to the standard?
因为标准说那些是保留的。这不是关于好坏的建议。这是标准的决定。他们为什么决定这个?我想第一批编译器在标准化之前就已经非正式地使用过这些约定。
从MSDN:
在所有范围内,C ++实现均保留在标识符的开头使用两个连续的下划线字符(__)或使用单个下划线后跟一个大写字母。对于具有文件范围的名称,应避免使用前导下划线后跟小写字母,因为这可能与当前或将来的保留标识符冲突。
这意味着您可以使用单个下划线作为成员变量前缀,只要后面带有小写字母即可。
这显然取自C ++标准的17.4.3.1.2节,但是我找不到在线完整标准的原始资料。
另请参阅此问题。