C/C++开发规范之一
来源:互联网 发布:png软件下载 编辑:程序博客网 时间:2024/06/05 04:20
[内部规则]:宏定义、函数声明集中放在头文件或文件头,全局变量定义和声明只能放在文件头。
[说明]:禁止在源文件中随处定义或声明,全局变量定义和声明统一放在源文件的开始。源文件前面的顺序应该是:包含的头文件、内部全局变量定义、外部全局变量定义、外部全局变量声明、内部函数声明、外部函数声明。
[规则]:源文件头部应进行注释,列出:版权说明、文件名、修改日志等。
[内部规则]:使用下面的文件头格式,对文件进行修改后,要更新文件头的信息。
/** @file file.h
* @noteHangZhou Hikvision Digital Technology Co., Ltd. All Right Reserved.
* @brief这里填写本文件的摘要。
*
* @author xxx
* @date 2004/02/14
*
* @note下面的note和warning为可选项目,但历史记录必选
* @note这里填写本文件的详细功能描述和注解
* @note历史记录:
* @note2011/06/08 V2.0.0 xxx添加了一个导出接口
*
* @warning这里填写本文件相关的警告信息
*/
[建议]:命名规范必须与所使用的系统风格保持一致,比如采用UNIX的全小写加下划线的风格或大小写混排的方式,不要使用大小写与下划线混排的方式,用作特殊标识如标识成员变量或全局变量的m_和g_,其后加上大小写混排的方式是允许的。
[示例]:Add_User不允许,add_user、AddUser、m_AddUser允许。
[说明]:根据系统风格,嵌入式Linux编程使用UNIX的全小写加下划线的风格。这里以下面的内部规则为准。
[内部规则]:标识符命名使用UNIX的全小写加下划线的风格,单词可使用缩写。包括文件名、函数名、变量名。
[示例]:int add_user(void);
[内部规则]:宏定义、枚举定义全部使用大写,typedef定义的类型全部使用大写。
[内部规则]:变量名使用名词或形容词+名词。
[内部规则]:全局变量名加g_前缀。
[示例]:int g_old_value;
[内部规则]:布尔型变量名加b_前缀。
[示例]:int b_main_chan;
[规则]:避免使用不易理解的数字,用有意义的标识来替代。涉及物理状态或者含有物理意义的常量,不应直接使用数字,必须用有意义的枚举或宏来代替。
[示例]:如下的程序可读性差。
if (Trunk[index].trunk_state == 0)
{
Trunk[index].trunk_state =1;
... // program code
}
应改为如下形式。
#define TRUNK_IDLE 0
#define TRUNK_BUSY 1
if (Trunk[index].trunk_state == TRUNK_IDLE)
{
Trunk[index].trunk_state =TRUNK_BUSY;
... // program code
}
1[规则]:不要使用难懂的技巧性很高的语句,除非很有必要时。
[说明]:高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。
[示例]:如下表达式,考虑不周就可能出问题,也较难理解。
* stat_poi ++ += 1;
* ++ stat_poi += 1;
应分别改为如下。
*stat_poi += 1;
stat_poi++; // 此二语句功能相当于“ * stat_poi ++ += 1;”
++ stat_poi;
*stat_poi += 1; // 此二语句功能相当于“ * ++ stat_poi += 1;”
1[规则]:switch语句必须有default分支。
1[建议]:循环体内工作量最小化。[建议]:在多重循环中,应将最忙的循环放在最内层。
[说明]:减少CPU切入循环层的次数。
[示例]:如下代码效率不高。
for (row = 0; row < 100; row++)
{
for (col = 0; col < 5;col++)
{
sum += a[row][col];
}
}
可以改为如下方式,以提高效率。
for (col = 0; col < 5; col++)
{
for (row = 0; row <100; row++)
{
sum += a[row][col];
}
}
[说明]:应仔细考虑循环体内的语句是否可以放在循环体之外,使循环体内工作量最小,从而提高程序的时间效率。
[示例]:如下代码效率不高。
for (ind = 0; ind< MAX_ADD_NUMBER; ind++)
{
sum += ind;
back_sum = sum; /* backupsum */
}
语句“back_sum =sum;”完全可以放在for语句之后,如下。
for (ind = 0; ind< MAX_ADD_NUMBER; ind++)
{
sum += ind;
}
back_sum = sum; /* backup sum*/
[建议]:避免循环体内含判断语句,应将循环语句置于判断语句的代码块之中。
[说明]:目的是减少判断次数。循环体中的判断语句是否可以移到循环体外,要视程序的具体情况而言,一般情况,与循环变量无关的判断语句可以移到循环体外,而有关的则不可以。
[示例]:如下代码效率稍低。
for (ind = 0; ind< MAX_RECT_NUMBER; ind++)
{
if (data_type ==RECT_AREA)
{
area_sum += rect_area[ind];
}
else
{
rect_length_sum +=rect[ind].length;
rect_width_sum +=rect[ind].width;
}
}
因为判断语句与循环变量无关,故可如下改进,以减少判断次数。
if (data_type == RECT_AREA)
{
for (ind= 0; ind < MAX_RECT_NUMBER; ind++)
{
area_sum += rect_area[ind];
}
}
else
{
for (ind= 0; ind < MAX_RECT_NUMBER; ind++)
{
rect_length_sum +=rect[ind].length;
rect_width_sum += rect[ind].width;
}
}
[建议]:尽量用乘法或其它方法代替除法,特别是浮点运算中的除法。
[内部规则]:尽量用乘法或其它方法代替除法,禁止浮点运算除法。
[说明]:浮点运算除法要占用较多CPU资源。
[示例]:如下表达式运算可能要占较多CPU资源。
#define PAI 3.1416
radius = circle_length / (2 * PAI);
应如下把浮点除法改为浮点乘法。
#define PAI_RECIPROCAL (1 /3.1416 ) // 编译器编译时,将生成具体浮点数[h2]
radius = circle_length * PAI_RECIPROCAL / 2;
[内部规则]:用“==”比较变量与某个值是否相等时,统一把值放在“==”的左侧。
[说明]:把要比较的值放在“==”的左侧,这样可避免将“==”错写成“=”。
[示例]:if (0 == value)
[规则]:严禁使用未经初始化的变量作为右值。
[说明]:特别是在C/C++中引用未经赋值的指针,经常会引起系统崩溃。
[规则]:严禁局部变量与全局变量同名。
[说明]:若使用了较好的命名规则,那么此问题可自动消除。
[建议]:使用严格形式定义的、可移植的数据类型,尽量不要使用与具体硬件或软件环境关系密切的变量。
[说明]:使用标准的数据类型,有利于程序的移植。
[示例]:假如认为如上的_PERSON结构元素过多,那么可如下对之划分。
typedef struct PERSON_BASE_INFO_STRU
{
unsigned char name[8];
unsigned char age;
unsigned char sex;
} PERSON_BASE_INFO;
typedef struct PERSON_ADDRESS_STRU
{
unsigned char addr[40];
unsigned char city[15];
unsigned char tel;
} PERSON_ADDRESS;
typedef struct PERSON_STRU
{
PERSON_BASE_INFOperson_base;
PERSON_ADDRESSperson_addr;
} PERSON;
[建议]:结构的设计要尽量考虑向前兼容和以后的版本升级,并为某些未来可能的应用保留余地(如预留一些空间等)。
[说明]:软件向前兼容的特性,是软件产品是否成功的重要标志之一。如果要想使产品具有较好的前向兼容,那么在产品设计之初就应为以后版本升级保留一定余地,并且在产品升级时必须考虑前一版本的各种特性。
[规则]:当声明用于分布式环境或不同CPU间通信环境的数据结构时,必须考虑机器的字节顺序、使用的位域及字节对齐等问题。
[说明]:在声明结构体的地方,必须使用#pragma pack(n)/#pragma pack()对指定对齐方式。
[说明]:比如Intel CPU与68360 CPU,在处理位域及整数时,其在内存存放的“顺序”正好相反。
示例:假如有如下短整数及结构。
unsigned short int exam;
typedef struct EXAM_BIT_STRU
{ /* Intel68360 */
unsigned int A1: 1; /*bit 0 7 */
unsigned int A2: 1; /*bit 1 6 */
unsigned int A3: 1; /*bit 2 5 */
} EXAM_BIT;
如下是Intel CPU生成短整数及位域的方式。
内存: 0 1 2 ... (从低到高,以字节为单位)
exam exam低字节 exam高字节
内存: 0 bit 1 bit 2 bit ... (字节的各“位”)
EXAM_BIT A1 A2 A3
如下是68360 CPU生成短整数及位域的方式。
内存: 0 1 2 ... (从低到高,以字节为单位)
exam exam高字节 exam低字节
内存: 7 bit 6 bit 5 bit ... (字节的各“位”)
EXAM_BIT A1 A2 A3
说明:在对齐方式下,CPU的运行效率要快得多。
示例:如下图,当一个long型数(如图中long1)在内存中的位置正好与内存的字边界对齐时,CPU存取这个数只需访问一次内存,而当一个long型数(如图中的long2)在内存中的位置跨越了字边界时,CPU存取这个数就需要多次访问内存,如i960cx访问这样的数需读内存三次(一个BYTE、一个SHORT、一个BYTE,由CPU的微代码执行,对软件透明),所有对齐方式下CPU的运行效率明显快多了。
1 8 16 24 32
----------------- -------- --------
|long1 | long1 | long1 | long1 |
----------------- -------- --------
| | | | long2 |
----------------- -------- --------
|long2 | long2 | long2 | |
----------------- -------- --------
[内部规则]:应用程序代码使用统一的自定义数据类型,如INT8、UINT32、BOOL等。
[说明]:为保持代码统一风格,应用程序代码中的变量类型统一使用自定义的数据类型。例如:无符号整型统一使用UINT8、UINT16、UINT32;有符号整型统一使用INT8、INT16、INT32;由于C语言中没有预定义的布尔类型,应用层使用BOOL(typedef int BOOL)。
[建议]:编写可重入函数时,应注意局部变量的使用。
[说明]:编写C/C++语言的可重入函数时,不应使用static局部变量,否则必须经过特殊处理,才能使函数具有可重入性。
[建议]:如果参数是指针,且仅作输入用,则应在类型前加const,以防止该指针在函数体内被意外修改。
[内部规则]:如果参数是指针,且仅作输入用,则应在类型前加const,以防止该指针在函数体内被意外修改。
[示例]:
void StringCopy(char *strDestination,const char *strSource);
[建议]:如果输入参数以值传递的方式传递对象,C++则宜改用“const &”方式来传递,这样可以省去临时对象的构造和析构过程,从而提高效率。
[内部规则]:如果输入参数以值传递的方式传递对象,C++则宜改用“const&”方式来传递,这样可以省去临时对象的构造和析构过程,从而提高效率。
[内部规则]:返回值为void类型的函数也要有return语句。
[规则]:用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。
[说明]:在C++标准中,new申请内存失败时默认抛出std::bad_alloc,如果要返回NULL值,可使用std::nothrow进行显示声明。
[说明]:1993年前,C++一直要求在内存分配失败时operator new要返回0,现在则是要求operatornew抛出std::bad_alloc异常。很多C++程序是在编译器开始支持新规范前写的。C++标准委员会不想放弃那些已有的遵循返回0规范的代码,所以他们提供了另外形式的operator new以继续提供返回0功能。这些形式被称为“无抛出”,因为他们没用过一个throw,而是在使用new的入口点采用了nothrow对象:
class widget { ... };
widget *pw1 = new widget;// 分配失败抛出std::bad_alloc
if (pw1 == 0) ... // 这个检查一定失败
widget *pw2 = new (nothrow) widget; //若分配失败返回0
if (pw2 == 0) ... // 这个检查可能会成功
不管是用“正规”(即抛出异常)形式的new还是“无抛出”形式的new,重要的是你必须为内存分配失败做好准备。
[建议]:在编写代码之前,应预先设计好程序调试与测试的方法和手段,并设计好各种调测开关及相应测试代码如打印函数等。
[内部规则]:在编写代码之前,应预先设计好程序调试与测试的方法和手段,并设计好各种调测开关及相应测试代码如打印函数等。
- C/C++开发规范之一
- C程序开发规范
- object-c开发规范
- C程序开发规范.doc
- Objective-C开发编码规范
- Objective-C开发编码规范
- Objective-C开发编码规范
- Objective-C开发编码规范
- Objective-C开发编码规范
- Objective-C开发编码规范
- Objective-C开发编码规范
- Objective-C开发编码规范
- objective-c开发编码规范
- Objective-C开发编码规范
- Objective-C开发编码规范
- Objective-C开发编码规范
- Objective-C开发编码规范
- Objective-C开发编码规范
- poj 2804 词典 (字典树 或者 快排+二分)
- 那些与鸡缸杯且行且珍惜的人
- hadoop出现ava.lang.ClassNotFoundException: org.codehaus.jackson.map.JsonMappingException
- CUGBACM_Summer_Tranning2【二维线段树】
- IOS-网络请求
- C/C++开发规范之一
- POJ 1047Round and Round We Go——大数乘法+匹配
- 精通安卓性能优化-第七章(三)
- Writing Audit Plugins
- 基本类型 包装类型 堆与栈 的区别
- java 身份证15转18
- 巧用dblink结合oracle快照实现两台服务器的数据同步
- 过滤器,监听器,拦截器的区别
- 关于概率的面试题