C#(或可能只是.NET)似乎建议使用下划线,比如_foo。这在C++标准中允许吗?
std
命名空间中的所有内容都是保留的。(尽管可以添加模板特化。)来自2003年的C++标准:
17.4.3.1.2 全局名称 [lib.global.names]E
开头,后跟数字或大写字母的名称:is
或 to
开头,后跟小写字母的名称LC_
开头,后跟大写字母的名称f
或 l
结尾的所有现有数学函数的名称SIG
开头,后跟大写字母的名称SIG_
开头,后跟大写字母的名称str
、mem
或 wcs
开头,后跟小写字母的名称PRI
或 SCN
开头,后跟任何小写字母或 X
的名称_t
结尾的名称_t
结尾命名标识符,因为这是POSIX标准保留的。_t
结尾的标识符的规定让我感到非常惊讶。我认为这是POSIX标准(还不确定)寻求澄清和官方章节的规定。这来自于GNU libtool manual,列出了保留的名称。避免命名冲突的规则在C++标准(见Stroustrup书籍)和C++大师(Sutter等人)提到过。
因为我不想处理情况,想要一个简单的规则,所以我设计了一个个人的规则,既简单又正确:
当给一个符号命名时,如果你遵循以下规则,就可以避免与编译器/操作系统/标准库发生冲突:
当然,将代码放在唯一的名称空间中有助于避免冲突(但无法防止恶意宏)。
(我使用宏,因为它们是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]
不以下划线开头的字面量后缀标识符保留供将来标准化使用。
除非您考虑到一个以一个下划线开头并后跟小写字母的名称如果在全局命名空间中未被定义,否则这个最后一条款很令人困惑...
__attribute__
)。 - Ruslan1234567L
或4.0f
这样的字面值;如果我没记错,这是指ohttp://en.cppreference.com/w/cpp/language/user_literal - Jason S至于问题的另一部分,通常将下划线放在变量名的末尾,以免与任何内部内容冲突。
即使在类和命名空间中也这样做,因为我只需要记住一个规则(与“在全局范围内名称的结尾,在其他地方名称的开头”相比)。
是的,在标识符中可以使用下划线。我相信规则是:第一个字符可以使用a-z、A-Z、_中的任意一个,后面的字符可以使用+0-9。
在C代码中,下划线前缀很常见——单个下划线表示“私有”,双下划线通常保留给编译器使用。
_t
- POSIX 2008标准,2.2.2
在C++中,几乎所有与POSIX相关的问题都可以通过命名空间来避免。
这也是为什么C++标准可以添加大量的符号,如std::enable_if_t
,而不会破坏POSIX兼容性的原因。
int x; // OK
int x_; // OK
int _x; // RESERVED
int x__; // RESERVED (OK in C)
int __x; // RESERVED
int _X; // RESERVED
int assert; // RESERVED (macro name)
int x_t; // RESERVED (only by POSIX)
namespace {
int y; // OK
int y_; // OK
int _y; // OK
int y__; // RESERVED (OK in C, ignoring namespaces)
int __y; // RESERVED
int _Y; // RESERVED
int assert; // RESERVED (macro name)
int y_t; // OK
}
y
的规则适用于命名空间和未命名空间。
无论哪种情况,在下面的命名空间中,全局命名空间的规则不再适用(参见[namespace.unnamed])。y
的规则也适用于类、函数等标识符;除了全局作用域之外的任何地方。assert
在这里不像函数样式的宏那样使用,但该名称是保留的。这也是为什么proposal P2884考虑在C++26中将其作为关键字,并取得了一些成功。
_
本身呢?_
来表示某些变量或函数参数未被使用。然而,你可以通过以下方式避免这种情况:void foo(T _) { /* ... */ }
// replace with:
void foo(T) { /* ... */ }
std::scoped_lock _{mutex};
// replace with:
std::scoped_lock lock{mutex};
p
强制转换为 void
,例如 (void)p
,如果你只是想消除关于 p
未使用的警告,并且需要与 C 兼容。请参阅 为什么将未使用的返回值强制转换为 void?。