5-2源程序中关系较为紧密的代码应尽可能相邻。
(强制)
说明:
便于程序阅读和查找。
错误示例:
rect.length=10;
char_poi=str;
rect.width=5;
正确示例:
rect.length=10;
rect.width=5;//矩形的长与宽关系较密切,放在一起。
char_poi=str;
5-3不要使用难懂的技巧性很高的语句,除非很有必要时。
(强制)
说明:
高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。
错误示例:
*stat_poi+++=1;
*++stat_poi+=1;
正确示例:
*stat_poi+=1;
stat_poi++;//此二语句功能相当于“*stat_poi+++=1;”
++stat_poi;
*stat_poi+=1;//此二语句功能相当于“*++stat_poi+=1;”
6数据类型
5-1禁止数据类型隐性地从高精度向低精度转换(强制)
例如int转换为short型或者char型。
double型转换为float型。
7常量
7-1C或者C++文件中,除允许出现-1,0,1三个数字外,其他数字都必须以常量方式定义,同一类常量应该统一格式,当-1,0,1有非常具体的意义时,也应该以常量代替。
(强制)
所有有特殊意义的数字都应该使用使用常量代替。
魔幻数字有百害而无一利,应该完全杜绝使用,特殊情况下可以使用数字。
例如strncpy(dest,src,5);
数字0主要可能出现在循环起始、数据结构初始化等地方。
-1主要出现在与函数结果比较的地方。
1应该是可以不需要出现的,不过有的地方确实以1为下标的。
给数组连续赋值和从数组中连续读取值可以采用以下方法实现:
intindex=0;
a=array[index++];
b=array[index++];
c=array[index++];
这种方式比以下方式:
a=array[0];
b=array[1];
c=array[2];
好一些,好处如下:
(1)如果下标需要修改为从1开始,那么只需要修改index=1即可,而第二种方法需要逐个修改。
(2)程序更加整齐,眼睛瞟一下就能够发现异常情况,特别是在项数比较多的情况下,只需要检查左边即可,右边都是一样的。
第二种情况需要检查左右两边,容易出错。
(3)如果数据内容顺序做了修改,只需要挪动相应的程序行即可,第二种方法必须修改索引。
7-2避免直接使用字符串,大部分地方可以用常量代替,有些地方可以以整数代替(即字符串的索引)。
(建议)
当前公司的业务主要是处理数值,字符串主要用做提示和说明信息,对计算机来说,处理整数的效率比处理字符串的效率不止高2个数量级。
字符串中涉及到空白,大小写,编码等情况,容易出错。
例如需要显示无效的参数,不直接使用“invalidparam”
而是使用常数:
#defineINVALID_PARAM“invalidparam”
或者定义数组:
staticcharerrmsg[]={“invalidparam”};
#defineINVALID_PARAM0
使用字符串“20080102083445”表示时间,可以改为用time_t或者其他时间类或者结构来表示。
8变量、结构
8-1绝大部分情况下禁止使用系统级的全局变量,而文件级的静态只读的全局变量则是可以使用的,函数库中不能输出全局变量。
(强制)
全局变量在多线程应用中可能带来很多问题,推荐使用其他开发软件中的方法。
定义一个结构(在C++中可以定义一个这样的类)
typedefstruct_context
{
/*需要用作全局变量内容放在这里*/
}CONTEXT;
系统中绝大部分函数都把这个参数(CONTEXT*ctx)作为第一个参数,这样就没有全局变量的必要了。
特殊情况的例子如下:
系统中的所有错误信息可以通过只读的全局变量集中存放,放在一个c/cpp文件中,以static标识。
例如:
staticcharerrmsg[]={“error1”,
“error2”};
这种做法是无害的。
这种方式通常用来保存错误信息或者提示信息。
8-2结构的定义(强制)
结构的定义要求使用unix中的定义方式,全部以小写表示。
例如:
structtimeval{
longtv_sec;/*secondssinceJan.1,1970*/
longtv_usec;/*/*andmicroseconds*/
};
结构的定义方式为强制,结构中成员变量的定义方式建议使用结构名的缩写,加上下划线再加变量。
9类
9-1类名定义(建议)
类的名字必须由一个或数个能表达该类的意思的大写字母开头而其它字母都小写的单词或缩写组成。
这样能使这个类的名称能更容易被理解,
例如:
classStudents
{
public:
intgetName(char*buf,int*len);
intsetName(char*buf,intlen);
private:
charname[MAX_NAME_LEN];
};
9-2成员变量(强制)
变量名由一个或数个能表达该变量的意思的单词组成,使用大小写混合的方式,每一个词是小写,后面的词第一个字母大写,其它小写。
9-3成员函数(强制)
成员函数的名称应该是一个动词,使用大小写混合的方式,每一个词是小写,后面的词第一个字母大写,其它小写。
9-4禁止在C++类中使用非基本类型的静态成员变量。
(强制)
如果在类中使用其他类的实例作为静态变量,系统在连接和初始化时可能会出现问题,可以使用静态非基本类型的成员变量指针。
非基本类型的指针仍然是基本类型。
10宏
10-1宏定义(建议)
宏定义应该全部使用大写字母,用下划线隔开多个词汇,当宏中语句比较多时,推荐使用以下方法定义,例如:
#definePERF_CHECK(x)do{if((x)==0)\
Xxxx;\
else\
Xxxx;\
}while(0)
即用do{}while(0),把语句包起来,linux的源代码中基本上都是这样做的,这是防止宏扩展时出问题的最好办法,而且不会增加运行时CPU的负担,因为do{}while(0)语句会被编译器优化掉。
11函数、过程
11-1函数的规模尽量限制在200行以内。
(建议)
说明:
不包括注释和空格行。
12错误代码
12-1错误代码的定义。
(强制)
应该用数值来表示错误代码,其格式应该一样,例如用ERR作为前缀,后面用动宾结构说明原因,同类的错误应该合并,例如:
#defineERR_BASE1000
#defineERR_OPEN_FILE(ERR_BASE+1)
#defineERR_CREATE_FILE(ERR_BASE+2)
错误内容可以通过一个函数,例如strerror返回。
公司将来可以收集所有的错误代码和文字信息,统一命名并应用到所有项目中。
13调试
13-1以DEBUG宏是否定义产生调试版本和发布版本。
(强制)
DEBUG宏是一个总开关,可以在DEBUG宏的基础上定义其他宏。
如果DEBUG宏没有定义,那么其他宏都是没有定义的。
即使DEBUG宏定义了,可能还必须定义其他宏来调试不同的内容。
例如定义DEBUG_DB来表示调试数据库的相关内容。
13-2使用VERIFY宏。
(建议)
#ifdefDEBUG
#defineVERIFY(e)\
(!
(e)?
(void)0:
\
(fprintf(stderr,"Verifyfailure:
%s:
%d:
\"%s\"",\
__FILE__,__LINE__,#e),abort()))
#else
#defineVERIFY(e)(e)
#endif
如果定义了DEBUG宏,这个宏有效。
否则直接执行表达式e。
这个宏当e的值为非0时,将打印错误行和内容,并且退出。
如果遵循了函数的返回规范,把这个宏加到函数上,可以保证对每个函数的返回值都进行检查。
14内存管理
14-1内存管理应该遵循谁申请谁释放、谁提供申请方法谁就提供释放方法的原则。
(建议)
如果一个类或者模块提供了一个函数,内部包含了申请内存的功能。
应该同时提供一个函数,允许释放这些内存。
而不应该让调用程序通过free或者delete来释放内存。
这样有如下好处:
(1).该类或者模块内部可以改变内部申请和释放内存的方式,只需要申请和释放方式互相对应即可。
(2).外部调用程序不用关心类或者模块的内部实现,只需配对使用接口即可。
(3).出现内存泄漏时可以分别测试定位,降低了模块之间的藕合。
15实践建议
15-1应用中不直接使用C/C++语言中的数据类型
应用中不直接使用int、void*、char*类型除外的C/C++的数据类型。
int类型的使用主要用作索引、次数等,因为索引、次数都是从0开始,基本上不会使整数溢出。
不应该使用C++的bool类型,直接用整数代替,因为整数具有bool所