一、标识符定义规则
1.可以由数字、字母、下划线_、美元符号$组成
2.不能以数字开头
3.不能是关键字
4.区分大小写
二、常用标识符命名风格
1、unix like风格:单词用小写字母,每个单词直接用下划线‘_’分割,例如:text_mutex, kernerl_text_address。
2、小驼峰命名法:
当标识符是一个单词的时候,首字母小写,例如:name。
当标识符由多个单词组成的时候,第一个单词首字母小写,其他单词首字母大写,例如:firstName。
3、大驼峰命名法:
当标识符是一个单词的时候,首字母大写,例如:Student。
当标识符由多个单词组成的时候,每个单词的首字母大写,例如:GoodStudent。
4、匈牙利命名法:用这种方法命名的变量显示了数据类型,匈牙利命名主要包括三个部分:基本类型、一个或更多的前缀,一个限定词。这种命名法最初在20世纪80年代的微软公司广泛使用,并在win32API和MFC库中广泛使用,但匈牙利命名法存在较多的争议,不太建议使用该命名法。
三、标识符通用命名规则
原则3.1 标识符的命名要清晰明了,有明确含义,同时能使用完整的单词或被大家基本可以理解的单词缩写,避免使人产生误解。
说明:尽可能给出描述性名称,不要节约空间,让别人很快理解你的代码更重要。
示例:好的命名:
int error_number;
int number_of_completed_connection;
不好的命名:使用模糊的缩写或随意的字符:
int n;
int nerr;
int n_comp_conns;
原则3.2 除了常用的通用缩写以外,不使用单词缩写,不得使用汉语拼音。
说明:较短的单词可通过去掉“元音”形成缩写,较长的单词可取单词的头几个字母形成缩写,一些单词有大家公认的缩写,常用单词的缩写必须统一。协议中单词缩写与协议保持一致。对于某个系统使用的专用缩写应该在注释或者某处做统一处理。
示例:一些常见的可以缩写的例子:
addtion —> add answer —> ans array —> arr average—>ave argument —> arg
buffer —> buff 或 buf
clock —> clk
column —> col
control —> ctrl
command —> cmd
compare —> cmp
configuration —> cfg
count —> cnt
define —> def delete —> del destination—>dst 或 dest display—>disp device —> dev decode —> dec division —> div
frequency—>freq
error —> err environment —> env encode —> enc
hexademical —> hex header —> hdr
index —> idx image —> img initialize —> init increment —> inc length—>len
make —> mk maximum —> max message —> msg minumum —> min multiplication—>multi memory—>mem middle—>mid
number —> num
option—>opt
parameter —> para previous —> prev pointer —> ptr
register —> reg receiver—>recv return —> ret result—>res
source —> src stack—>stk string—>str subtraction—>sub semaphore —> sem statistic —> stat syncchronize —> sync
table —>tab temp —> tmp temporary—>tmp或temp time stamp—>ts
value—>val
规则3.1 产品/项目组内部应保持统一的命名风格。
说明:Unix like和 windows like风格均有其拥趸,产品应根据自己的部署平台,选择其中一种,并在产品内部保持一致。
例外:即使产品之前使用匈牙利命名法,新代码也不应当使用。
建议3.1 用正确的反义词命名具有互斥意义的变量或相反动作的函数。
示例:
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/receiver source/destination copy/paste up/down
建议3.2 尽量避免名字中出现数字编号,除非逻辑上的确需要编号。
错误示例:如下命名,使人产生疑惑。
#define EXAMPLE_0_TEST_
#define EXAMPLE_1_TEST_
正确示例:应改为有意义的单词命名。
#define EXAMPLE_UNIT_TEST_
#define EXAMPLE_ASSERT_TEST_
建议3.3 标识符前不应添加模块、项目、产品、部门的名称作为前缀。
说明:很多已有代码中已经习惯在文件名中增加模块名,这种写法类似匈牙利命名法,导致文件名不可读,并且带来带来如下问题:
- 第一眼看到的是模块名,而不是真正的文件功能,阻碍阅读;
- 文件名太长;
- 文件名和模块绑定,不利于维护和移植。若foo.c进行重构后,从a模块挪到b模块,若foo.c
- 中有模块名,则需要将文件名从a_module_foo.c改为b_module_foo.c。
建议3.4 平台/驱动等适配代码的标识符命名风格保持和平台/驱动一致。
说明:涉及到外购芯片以及配套的驱动,这部分的代码变动(包括为产品做适配的新增代码),应该保持原有的风格。
建议3.5 重构/修改部分代码时,应保持和原有代码的命名风格一致。
说明:根据源代码现有的风格继续编写代码,有利于保持总体一致。
四、文件命名规则
建议4.1 文件命名统一采用小写规范。
说明:因为不同操作系统对文件名大小写处理会不同(如MS的DOS、Windows系统不区分大小写,但是Linux系统则区分),所以代码文件命名建议统一采用全小写字母命名。多个单词之间使用下划线‘_’分隔。
五、变量命名规则
规则5.1 全局变量应增加 “g_” 前缀。
规则5.2 静态变量应增加 “s_” 前缀。
说明:增加 g_ 前缀或者 s_ 前缀,原因如下:
1、全局变量十分危险,通过前缀使得全局变量更加醒目,促使开发人员对这些变量的使用更加小心。
2、从根本上说,应当尽量不使用全局变量,增加 g_ 和 s_ 前缀,会使得全局变量的名字显得很丑陋,从而促使开发人员尽量少使用全局变量。
慎用全局变量,缺点如下:
1、全局变量破坏了函数的独立性和可移植性,使函数对全局变量产生依赖,存在耦合。
2、全局变量降低了函数代码的可读性和可维护性。
3、在并发环境中,使用全局变量会破坏函数的可重入性,需要增加额外的同步保护处理才能确保数据安全。
规则5.3 禁止使用单字节命名变量,但允许定义 i, j, k 等作为局部循环变量。
建议5.1 不建议使用匈牙利命名法。
说明:变量命名需要说明的是变量的含义,要能达到见名知意的目的,而不是变量的类型。在变量命名前增加类型说明,反而降低了变量的可读性;更麻烦的问题是,如果修改了变量的类型定义,那么所有使用该变量的地方都要修改。
匈牙利命名法是一种编程时的命名规范。基本原则是:变量名=属性+类型+对象描述。匈牙利命名法源于微软,然而却被很多人以讹传讹的使用。而现在即使是微软也不再推荐使用匈牙利命名法。历来对匈牙利命名法的一大诟病,就是导致了变量名难以阅读,这和本规范的指导思想也有冲突,所以本规范特意强调,变量命名不应采用匈牙利命名法,而应该想法使变量名为一个有意义的词或词组,方便代码的阅读。
建议5.2 局部变量的命名采用小驼峰命名法或者Linux内核命名法。使用名词或者形容词+名词方式命名变量。
示例:
//小驼峰命名法
int msgInfo;
int retCode;
//Linux内核命名法
int current_time;
六、函数命名规则
建议6.1 函数建议使用大驼峰命名法或者Linux内核命名法。
示例:
//大驼峰命名法
int EventBaseLoop();
int EventDispatch();
//Linux内核命名法
int event_base_loop();
int event_dsipatch();
建议6.2 函数命名应以函数要执行的动作命名,一般采用动词或者动词+名词的结构。
示例:
int GetCurrentDirectory();
int get_current_directory();
void SetValue(int value);
void set_value(int value);
建议6.3 函数指针除了前缀,其他按照函数的命名规则命名。
七、宏的命名规则
规则7.1 对于数值或者字符串等常量的定义,建议采用全大写的英文字母,单词之间加下划线‘_’的方式命名(枚举常量同样建议使用此方式定义)。
示例:
#define PI_ROUNDED 3.14
#define EVLIST_TIMEOUT 0x01
#define EVLIST_INSERTED 0x02
#define EVLIST_SIGNAL 0x04
#define EVLIST_ACTIVE 0x08
#define EVLIST_INTERNAL 0x10
#define EVLIST_INIT 0x80
#define LOCAL_IP "127.0.0.1"
规则7.2 除了头文件或者编译开关等特殊标识符定义,宏定义不能使用下划线 ‘_’ 开头和结尾。
说明:一般来说,下划线 ‘_’ 开头、结尾的宏都是一些内部的定义。
示例:
//头文件的宏定义保护,避免被重复包含
#ifndef COMMON_FUN_H_
#define COMMON_FUN_H_
...
#endif
//条件编译的宏定义,可以使用下划线'_'开头
#ifdef _DEBUG
...
#else
...
#endif
八、代码检视问题汇总
判断系统函数的返回值,直接写0即可。
说明:判断系统函数的返回值时,不能调用自定义的宏,确定好系统的返回值之后,直接写0或者-1即可。系统调用函数的返回值,一般情况下都是成功时返回0,失败时返回-1。
行函数命名应使用大驼峰风格或者Linux内核风格。
说明:函数命名应使用大驼峰风格,即:大小写混用,单词连在一起,不同单词间通过单词首字母来分开。也可以使用Linux内核风格的函数命名风格,但是必须要统一,不要二者混用。
结构体类型的定义使用大驼峰命名风格,结构体成员变量则使用小驼峰命名风格或者Linux内核风格。
typede struct {
int studNum; //也可以写成 stud_num
char gender[10];
int age;
int grade;
}Student;
指针符号位置
说明:指针符号应该靠近变量。
示例:
//错误写法
int* ptr;
int * ptr;
//正确写法
int *ptr;
复杂的表达式应该使用小括号表明优先级。
说明:存在多个不同的运算符时,为了避免可能存在的优先级问题,要将表达式用小括号括起来。
Log日志打印信息相同不利于分析定位问题。
说明:Log的打印信息可以帮助我们分析定位错误,如果多处的Log打印都一样,就会增加我们定位分析的难度,这不利于我们的开发。
局部变量的命名应使用小驼峰风格。
说明:局部变量的命名应使用小驼峰风格,即:大小写字母混用,单词连在一起,不同单词间通过首字母大写来分开,第一个首字母为小写。当然也可以使用Linux内核风格,但是命名风格需要统一,不要二者混用。
对全局变量的访问应考虑是否需要加锁。
说明:全局变量被多线程访问时,存在数据错误的可能性,在这种情况下,我们要限制线程对全局变量的访问,使得一个线程在访问全局变量时不受其他线程的影响。
代码排版
1、要注意代码排版的空格问题,要去掉多余的空格。
2、数据类型和指针符号(*)之间要有一个空格。例如:
int pInt = (int *)malloc(sizeof(int));
3、一行代码不足120个字符时,不需要换行。
编程规范
1.大括号内两端要留一个空格的空白。
int arr[] = { 1, 2, 3, 4, 5 };
2、函数形参中,不被改变的参数加 const 修饰词。
void func(const int *x, int y);
参考
《华为C语言编程规范(2826-2011.5).pdf》
《华为C&C++安全编程规范_V3.1.pdf》
《高质量C/C++编程指南(林锐-2001).pdf》