在 C++ 标识符中使用下划线的规则是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/228783/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What are the rules about using an underscore in a C++ identifier?
提问by Roger Lipscombe
It's common in C++ to name member variables with some kind of prefix to denote the fact that they're member variables, rather than local variables or parameters. If you've come from an MFC background, you'll probably use m_foo
. I've also seen myFoo
occasionally.
在 C++ 中,用某种前缀命名成员变量是很常见的,以表示它们是成员变量,而不是局部变量或参数。如果您有 MFC 背景,您可能会使用m_foo
. 我也myFoo
偶尔看到。
C# (or possibly just .NET) seems to recommend using just an underscore, as in _foo
. Is this allowed by the C++ standard?
C#(或可能只是 .NET)似乎建议只使用下划线,如_foo
. C++ 标准允许这样做吗?
采纳答案by Martin York
The rules (which did not change in C++11):
规则(在 C++11 中没有改变):
- Reserved in any scope, including for use as implementationmacros:
- identifiers beginning with an underscore followed immediately by an uppercase letter
- identifiers containing adjacent underscores (or "double underscore")
- Reserved in the global namespace:
- identifiers beginning with an underscore
- Also, everything in the
std
namespace is reserved. (You are allowed to add template specializations, though.)
- 在任何范围内保留,包括用作实现宏:
- 下划线开头的标识符后跟大写字母
- 包含相邻下划线(或“双下划线”)的标识符
- 保留在全局命名空间中:
- 下划线开头的标识符
- 此外,
std
命名空间中的所有内容都是保留的。(不过,您可以添加模板特化。)
From the 2003 C++ Standard:
来自 2003 C++ 标准:
17.4.3.1.2 Global names [lib.global.names]
Certain sets of names and function signatures are always reserved to the implementation:
- Each name that contains a double underscore (
__
) or begins with an underscore followed by an uppercase letter (2.11) is reserved to the implementation for any use.- Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.165
165)Such names are also reserved in namespace
::std
(17.4.3.1).
17.4.3.1.2 全局名称 [lib.global.names]
某些名称和函数签名集始终保留给实现:
- 每个包含双下划线 (
__
) 或以下划线开头后跟大写字母 (2.11) 的名称都保留给实现以供任何使用。- 每个以下划线开头的名称都保留给实现以用作全局命名空间中的名称。165
165)这样的名字也保留在命名空间
::std
(17.4.3.1)中。
Because C++ is based on the C standard (1.1/2, C++03) and C99 is a normative reference (1.2/1, C++03) these also apply, from the 1999 C Standard:
因为 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
, andva_end
.
7.1.3 保留标识符
每个头声明或定义在其相关子条款中列出的所有标识符,并可选地声明或定义在其相关的未来库方向子条款中列出的标识符和标识符,这些标识符始终保留用于任何用途或用作文件范围标识符。
- 所有以下划线和大写字母或另一个下划线开头的标识符始终保留供任何使用。
- 所有以下划线开头的标识符始终保留用作普通名称空间和标记名称空间中具有文件范围的标识符。
- 以下任何子条款(包括未来的库方向)中的每个宏名称都保留供指定的使用,前提是包含任何关联的头文件;除非另有明确说明(见 7.1.4)。
- 以下任何子条款(包括未来的库方向)中具有外部链接的所有标识符始终保留用作具有外部链接的标识符。154
- 在以下任何子条款(包括未来的库方向)中列出的每个具有文件范围的标识符都被保留用作宏名称,如果包含任何关联的标题,则保留用作相同名称空间中具有文件范围的标识符。
不保留其他标识符。如果程序在保留标识符的上下文中声明或定义标识符(7.1.4 允许的情况除外),或将保留标识符定义为宏名称,则行为未定义。
如果程序删除(使用
#undef
)上面列出的第一组中的标识符的任何宏定义,则行为未定义。154)与外部连接保留的标识符的列表包括
errno
,math_errhandling
,setjmp
,和va_end
。
Other restrictions might apply. For example, the POSIX standard reserves a lot of identifiers that are likely to show up in normal code:
其他限制可能适用。例如,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
orto
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
orl
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
, orwcs
followed by a lowercase letter are reserved- for additional string and array functions.
- Names beginning with
PRI
orSCN
followed by any lowercase letter orX
are reserved- for additional format specifier macros
- Names that end with
_t
are reserved- for additional type names.
- 以
E
大写开头的名称后跟数字或大写字母:- 可用于附加错误代码名称。
- 以小写字母开头
is
或to
后跟小写字母的名称- 可用于额外的字符测试和转换功能。
- 打头的名称
LC_
后跟一个大写字母- 可用于指定语言环境属性的附加宏。
- 以
f
或l
为 后缀的所有现有数学函数的名称- 对于分别对 float 和 long double 参数进行操作的相应函数。
SIG
以大写字母开头的名称是保留的- 用于其他信号名称。
SIG_
以大写字母开头的名称是保留的- 用于额外的信号操作。
- 以
str
,开头mem
或wcs
后跟小写字母的名称是保留的- 用于额外的字符串和数组函数。
- 以任何小写字母开头
PRI
或SCN
后跟或X
保留的名称- 用于其他格式说明符宏
- 以 结尾的名称
_t
是保留的- 用于其他类型名称。
While using these names for your own purposes right now might not cause a problem, they do raise the possibility of conflict with future versions of that standard.
虽然现在将这些名称用于您自己的目的可能不会造成问题,但它们确实增加了与该标准的未来版本发生冲突的可能性。
Personally I just don't start identifiers with underscores. New addition to my rule: Don't use double underscores anywhere, which is easy as I rarely use underscore.
我个人只是不以下划线开头标识符。我的规则的新增内容:不要在任何地方使用双下划线,这很容易,因为我很少使用下划线。
After doing research on this article I no longer end my identifiers with _t
as this is reserved by the POSIX standard.
在对本文进行研究后,我不再以标识符结尾,_t
因为这是 POSIX 标准保留的。
The rule about any identifier ending with _t
surprised me a lot. I think that is a POSIX standard (not sure yet) looking for clarification and official chapter and verse. This is from the GNU libtool manual, listing reserved names.
关于任何标识符结尾的规则_t
让我很惊讶。我认为这是一个 POSIX 标准(还不确定),正在寻找澄清和官方章节。这是来自GNU libtool 手册,列出了保留名称。
CesarB provided the following link to the POSIX 2004reserved symbols and notes 'that many other reserved prefixes and suffixes ... can be found there'. The POSIX 2008reserved symbols are defined here. The restrictions are somewhat more nuanced than those above.
CesarB 提供了以下指向POSIX 2004保留符号的链接,并指出“可以在那里找到许多其他保留的前缀和后缀……”。该 POSIX 2008保留符号在这里被定义。这些限制比上面的那些更微妙。
回答by paercebal
The rules to avoid collision of names are both in the C++ standard (see Stroustrup book) and mentioned by C++ gurus (Sutter, etc.).
避免名称冲突的规则在 C++ 标准(参见 Stroustrup 书)和 C++ 大师(Sutter 等)中都有提到。
Personal rule
个人规则
Because I did not want to deal with cases, and wanted a simple rule, I have designed a personalone that is both simple and correct:
因为不想处理案例,想要一个简单的规则,所以我设计了一个既简单又正确的个人规则:
When naming a symbol, you will avoid collision with compiler/OS/standard libraries if you:
命名符号时,如果您符合以下条件,将避免与编译器/操作系统/标准库发生冲突:
- never start a symbol with an underscore
- never name a symbol with two consecutive underscores inside.
- 切勿以下划线开头的符号
- 永远不要命名带有两个连续下划线的符号。
Of course, putting your code in an unique namespace helps to avoid collision, too (but won't protect against evil macros)
当然,将您的代码放在唯一的命名空间中也有助于避免冲突(但不会防止恶意宏)
Some examples
一些例子
(I use macros because they are the more code-polluting of C/C++ symbols, but it could be anything from variable name to class name)
(我使用宏是因为它们对 C/C++ 符号的代码污染更大,但它可以是从变量名到类名的任何东西)
#define _WRONG
#define __WRONG_AGAIN
#define RIGHT_
#define WRONG__WRONG
#define RIGHT_RIGHT
#define RIGHT_x_RIGHT
Extracts from C++0x draft
摘自 C++0x 草案
From the n3242.pdffile (I expect the final standard text to be similar):
从n3242.pdf文件(我希望最终的标准文本是相似的):
17.6.3.3.2 Global names [global.names]
Certain sets of names and function signatures are always reserved to the implementation:
— Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase letter (2.12) is reserved to the implementation for any use.
— Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.
17.6.3.3.2 全局名称 [global.names]
某些名称和函数签名集始终保留给实现:
— 每个包含双下划线 _ 或以下划线开头后跟大写字母 (2.12) 的名称都保留给实现以供任何使用。
— 每个以下划线开头的名称都保留给实现用作全局命名空间中的名称。
But also:
但是也:
17.6.3.3.5 User-defined literal suffixes [usrlit.suffix]
Literal suffix identifiers that do not start with an underscore are reserved for future standardization.
17.6.3.3.5 用户定义的文字后缀 [usrlit.suffix]
不以下划线开头的文字后缀标识符保留用于未来的标准化。
This last clause is confusing, unless you consider that a name starting with one underscore and followed by a lowercase letter would be Ok if notdefined in the global namespace...
最后一个子句令人困惑,除非您认为名称以一个下划线开头并后跟一个小写字母,如果未在全局命名空间中定义,则可以...
回答by Roger Lipscombe
From MSDN:
从MSDN:
Use of two sequential underscore characters ( __ ) at the beginning of an identifier, or a single leading underscore followed by a capital letter, is reserved for C++ implementations in all scopes. You should avoid using one leading underscore followed by a lowercase letter for names with file scope because of possible conflicts with current or future reserved identifiers.
在标识符的开头使用两个连续的下划线字符 ( __ ),或单个前导下划线后跟一个大写字母,是为所有范围内的 C++ 实现保留的。您应该避免使用一个前导下划线后跟一个小写字母作为具有文件范围的名称,因为可能与当前或将来的保留标识符发生冲突。
This means that you can use a single underscore as a member variable prefix, as long as it's followed by a lower-case letter.
这意味着您可以使用单个下划线作为成员变量前缀,只要它后跟一个小写字母即可。
This is apparently taken from section 17.4.3.1.2 of the C++ standard, but I can't find an original source for the full standard online.
这显然取自 C++ 标准的第 17.4.3.1.2 节,但我在网上找不到完整标准的原始来源。
See also this question.
另请参阅此问题。
回答by Max Lybbert
As for the other part of the question, it's common to put the underscore at the endof the variable name to not clash with anything internal.
至于问题的另一部分,通常将下划线放在变量名的末尾,以免与内部的任何内容发生冲突。
I do this even inside classes and namespaces because I then only have to remember one rule (compared to "at the end of the name in global scope, and the beginning of the name everywhere else").
我什至在类和命名空间中也这样做,因为我只需要记住一个规则(与“在全局范围内的名称末尾,以及其他任何地方名称的开头”相比)。
回答by John Millikin
Yes, underscores may be used anywhere in an identifier. I believe the rules are: any of a-z, A-Z, _ in the first character and those +0-9 for the following characters.
是的,下划线可以在标识符中的任何地方使用。我相信规则是:第一个字符中的 az、AZ、_ 中的任何一个,以及以下字符中的 +0-9。
Underscore prefixes are common in C code -- a single underscore means "private", and double underscores are usually reserved for use by the compiler.
下划线前缀在 C 代码中很常见——单个下划线表示“私有”,双下划线通常保留供编译器使用。