提问



在C ++中,用一些前缀命名成员变量来表示它们是成员变量而不是局部变量或参数这一事实很常见。如果你来自MFC背景,你可能会使用m_foo。我偶尔也见过myFoo


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

最佳参考


规则(在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_errhandlingsetjmpva_end



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



  • 以大写E开头的名称后跟一个数字或大写字母:


    • 可用于其他错误代码名称。


  • isto开头,后跟小写字母的名称


    • 可用于其他字符测试和转换功能。


  • LC_开头,后跟大写字母的名称


    • 可用于指定区域设置属性的其他宏。


  • 保留以fl为后缀的所有现有数学函数的名称


    • 分别用于对float和long double参数进行操作的相应函数。


  • 保留以SIG开头,后跟大写字母的名称


    • 获取更多信号名称。


  • 保留以SIG_开头,后跟大写字母的名称


    • 用于其他信号操作。


  • strmemwcs开头,后跟小写字母的名称被保留


    • 用于其他字符串和数组函数。


  • PRISCN开头的名称后跟任何小写字母或X保留


    • 用于其他格式说明符宏


  • _t结尾的名称被保留


    • 了解其他类型名称。




虽然现在将这些名称用于您自己的目的可能不会导致问题,但它们确实会增加与该标准的未来版本冲突的可能性。





我个人不会用下划线开始标识符。我的规则的新增内容:不要在任何地方使用双下划线,这很容易,因为我很少使用下划线。


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


关于以_t结尾的任何标识符的规则让我大吃一惊。我认为这是一个POSIX标准(尚不确定)寻找澄清和官方章节和经文。这是来自GNU libtool手册,列出了保留名称。[30]


CesarB提供了以下指向POSIX 2004保留符号的链接,并注意到可以在那里找到许多其他保留的前缀和后缀......。该
POSIX 2008保留符号在此处定义。这些限制比上述限制更为微妙。[31] [32]

其它参考1


避免名称冲突的规则都是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文件(我希望最终的标准文本类似):[33]



   17.6.3.3.2全局名称[[global.names]]

  
  某些名称和功能签名集始终保留给实现:

  
   - 包含双下划线_ _或以下划线后跟大写字母(2.12)开头的每个名称保留给实现以供任何使用。

  
   - 以下划线开头的每个名称都保留给实现,以用作全局名称空间中的名称。



但也:



   17.6.3.3.5用户定义的文字后缀[[usrlit.suffix]]

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



最后一个条款令人困惑,除非你认为如果在全局命名空间中定义了 not ,那么以一个下划线开头并后跟一个小写字母的名称将是OK

其它参考2


来自MSDN:[34]



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



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


这显然取自C ++标准的第17.4.3.1.2节,但我无法在线找到完整标准的原始来源。


另见这个问题。

其它参考3


至于问题的另一部分,将变量名的 end 放在下面是不与内部任何内容发生冲突的情况。


我甚至在类和名称空间内执行此操作,因为我只需要记住一条规则(与在全局范围内的名称末尾,以及其他地方名称的开头相比)。

其它参考4


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


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