2.我使用的C/C++编写规范之命名约定

自用的规范,参考自Google、华为与微软。
 


最重要的一致性规则是命名管理,命名风格直接可以直接确定命名实体是:类型、变量、函数、常量、宏等等,无需查找实体声明,我们大脑中的模式匹配引擎依赖于这些命名规则。
命名规则具有一定随意性,但相比按个人喜好命名,一致性更重要,所以不管你怎么想,规则总归是规则。
 
1. 通用命名规则
 
1.1 标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。
说明:尽可能给出描述性名称,不要节约空间,让别人很快理解你的代码更重要。
好的命名示例:

int num_errors;                 // Good.
int num_completed_connections;  // Good.

不好的命名,使用模糊的缩写或随意的字符:

int n;               // Bad - meaningless.
int nerr;            // Bad - ambiguous abbreviation.
int n_comp_conns;    // Bad - ambiguous abbreviation.

1.2 除了常见的通用缩写以外,不使用单词缩写,不得使用汉语拼音。
说明:较短的单词可通过去掉“元音”形成缩写,较长的单词可取单词的头几个字母形成缩写,一些单词有大家公认的缩写,常用单词的缩写必须统一。协议中的单词的缩写与协议保持一致。对于某个系统使用的专用缩写应该在注释或者某处做统一说明。
一些常见可以缩写的例子示例:

全名 缩写
argument Text
buffer buff
clock clk
command cmd
compare cmp
configuration cfg
device dev
error err
hexadecimal hex
increment inc
initialize init
maximum max
message msg
minimum min
parameter para
previous prev
register reg
semaphore sem
statistic stat
synchronize sync
temp tmp

   
1.3 用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。

示例 示例 示例
add/remove begin/end create/destroy
insert/delete first/last get/release
increment/decrement put/get add/delete
lock/unlock open/close min/max
old/new start/stop next/previous
source/target show/hide send/receive
source/destination copy/paste up/down

   
1.4 尽量避免名字中出现数字编号,除非逻辑上的确需要编号。
       示例:如下命名,使人产生疑惑。

#define EXAMPLE_0_TEST_
#define EXAMPLE_1_TEST_

应改为有意义的单词命名:

#define EXAMPLE_UNIT_TEST_
#define EXAMPLE_ASSERT_TEST_

 
1.5 标识符前不应添加模块、项目、产品、部门的名称作为前缀。
说明:很多已有代码中已经习惯在文件名中增加模块名,这种写法类似匈牙利命名法,导致文件名不可读,并且带来带来如下问题:
1)第一眼看到的是模块名,而不是真正的文件功能,阻碍阅读;
2)文件名太长;
3)文件名和模块绑定,不利于维护和移植。若foo.c进行重构后,从a模块挪到b模块,若foo.c中有模块名,则需要将文件名从a_module_foo.c改为b_module_foo.c。
 
1.6 平台/驱动等适配代码的标识符命名风格保持和平台/驱动一致。
       说明:涉及到外购芯片以及配套的驱动,这部分的代码变动(包括为产品做适配的新增代码),应该保持原有的风格。
 
1.7 重构/修改部分代码时,应保持和原有代码的命名风格一致。
       说明:根据源代码现有的风格继续编写代码,有利于保持总体一致。
   
   
2.文件命名
因为不同系统对文件名大小写处理会不同(如MS的DOS、Windows系统不区分大小写,但是Linux系统则区分),文件名要全部小写,可以包含下划线(_)或短线(-),按项目约定来。
可接受的文件命名:
my_useful_class.cpp
my-useful-class.cpp
myusefulclass.cpp
C++文件以.cpp结尾,头文件以.h结尾。
不要使用已经存在于/usr/include下的文件名(对 UNIX、Linux 等系统而言), 如 db.h。
通常,尽量让文件名更加明确,http_server_logs.h 就比 logs.h 要好,定义类时文件名一般成对出现,如 foo_bar.h 和 foo_bar.cpp,对应类 FooBar。
内联函数必须放在.h 文件中,如果内联函数比较短,就直接放在.h 中。如果代码比较长,可以放到以-inl.h 结尾的文件中。对于包含大量内联代码的类,可以有三个文件:

url_table.h     // The class declaration.
url_table.cc    // The class definition.
url_table-inl.h // Inline functions that include lots of code.

 
 
3.类型命名
类型命名每个单词以大写字母开头,不包含下划线:MyExcitingClass、MyExcitingEnum。
所有类型命名,包括类、结构体、类型定义(typedef)与枚举都使用相同约定,例如:

// classes and structs
class UrlTable { 
class UrlTableTester {
struct UrlTableProperties { 

// typedefs
typedef hash_map<UrlTableProperties *, string> PropertiesMap;

// enums
enum UrlTableErrors {

 
 
4.变量命名
    采用UNIX风格。变量名一律小写,单词间以下划线相连,类的成员变量以下划线结尾,如
my_exciting_local_variable、my_exciting_member_variable_。
    使用名词或者形容词+名词方式命名变量。
  
4.1 普通变量命名
    举例:

string table_name; // OK - uses underscore.
string tablename;  // OK - all lowercase.
string tableName;  // Bad - mixed case.

4.2 类数据成员
    结构体的数据成员可以和普通变量一样,不用像类那样接下划线:

struct UrlTableProperties {
  string name;
  int num_entries;
}

 
4.3 全局变量与静态变量
    全局变量以 g_ 为前缀。
    静态变量以s_ 为前缀。
    说明:增加g_前缀或者s_前缀,原因如下:
    首先,全局变量十分危险,通过前缀使得全局变量更加醒目,促使开发人员对这些变量的使用更加小心。
    其次,从根本上说,应当尽量不使用全局变量,增加g_和s_前缀,会使得全局变量的名字显得很丑陋,从而促使开发人员尽量少使用全局变量。
 
4.4 禁止使用单字节命名变量,但允许定义i、j、k作为局部循环变量。
 
4.5 禁止使用匈牙利命名法。
    说明:变量命名需要说明的是变量的含义,而不是变量的类型。在变量命名前增加类型说明,反而降低了变量的可读性;更麻烦的问题是,如果修改了变量的类型定义,那么所有使用该变量的地方都需要修改。
    匈牙利命名法源于微软,然而却被很多人以讹传讹的使用。而现在即使是微软也不再推荐使用匈牙利命名法。历来对匈牙利命名法的一大诟病,就是导致了变量名难以阅读,这和本规范的指导思想也有冲突,所以本规范特意强调,变量命名不得采用匈牙利命名法,而应该想法使变量名为一个有意义的词或词组,方便代码的阅读。
  
  
5.常量命名
    在名称前加 k,例如:kDaysInAWeek。
    所有编译时常量(无论是局部的、全局的还是类中的)和其他变量保持些许区别,k 后接大写字母开头的单词:

const int kDaysInAWeek = 7;

 
 
6.函数命名
    函数命名应以函数要执行的动作命名,一般采用动词或者动词+名词的结构。
    示例:找到当前进程的当前目录

DWORD GetCurrentDirectory( DWORD BufferLength, LPTSTR Buffer );

函数指针除了前缀,其他按照函数的命名规则命名。
普通函数(regular functions,这里与访问函数等特殊函数相对)大小写混合,存取函数(accessors and mutators)则要求与变量名匹配:MyExcitingFunction()、MyExcitingMethod()、my_exciting_member_variable()、set_my_exciting_member_variable()。
 
6.1 普通函数
    函数名以大写字母开头,每个单词首字母大写,没有下划线:
    AddTableEntry()
    DeleteUrl()
 
6.2 存取函数
    存取函数要与存取的变量名匹配,这儿摘录一个拥有实例变量 num_entries_的类:

class MyClass {
  public:
  ...
  int num_entries() const { return num_entries_; }
  void set_num_entries(int num_entries) { num_entries_ = num_entries; }
  private:
  int num_entries_;
};

其他短小的内联函数名也可以使用小写字母,例如,在循环中调用这样的函数甚至都不需要缓存其值,小写命名就可以接受。
 
 
7.命名空间
 命名空间的名称是全小写的,其命名基于项目名称和目录结构:google_awesome_project。
 
 
8.枚举命名
    枚举值应全部大写,单词间以下划线相连:MY_EXCITING_ENUM_VALUE。
    枚举名称属于类型,因此大小写混合:UrlTableErrors。

enum UrlTableErrors {
  OK = 0,
  ERROR_OUT_OF_MEMORY,
  ERROR_MALFORMED_INPUT,
};

 
 
9.宏命名
    采用全大写字母,单词之间加下划线“_”的方式命名。例如:
    MY_MACRO_THAT_SCARES_SMALL_CHILDREN\par
    除了头文件或编译开关等特殊标识定义,宏定义不能使用下划线“_”开头和结尾。
 
(未完待续)

猜你喜欢

转载自blog.51cto.com/13807182/2130051