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下面的notewarning为可选项目,但历史记录必选

*    @note这里填写本文件的详细功能描述和注解

*    @note历史记录:

*    @note2011/06/08 V2.0.0 xxx添加了一个导出接口

*

*    @warning这里填写本文件相关的警告信息

*/

[建议]:命名规范必须与所使用的系统风格保持一致,比如采用UNIX的全小写加下划线的风格或大小写混排的方式,不要使用大小写与下划线混排的方式,用作特殊标识如标识成员变量或全局变量的m_g_,其后加上大小写混排的方式是允许的。

[示例]Add_User不允许,add_userAddUserm_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 CPU68360 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 |    |

       ----------------- -------- --------

[内部规则]:应用程序代码使用统一的自定义数据类型,如INT8UINT32BOOL等。

[说明]:为保持代码统一风格,应用程序代码中的变量类型统一使用自定义的数据类型。例如:无符号整型统一使用UINT8UINT16UINT32;有符号整型统一使用INT8INT16INT32;由于C语言中没有预定义的布尔类型,应用层使用BOOLtypedef int BOOL)。

[建议]:编写可重入函数时,应注意局部变量的使用。

[说明]:编写C/C++语言的可重入函数时,不应使用static局部变量,否则必须经过特殊处理,才能使函数具有可重入性。

[建议]:如果参数是指针,且仅作输入用,则应在类型前加const,以防止该指针在函数体内被意外修改。

[内部规则]:如果参数是指针,且仅作输入用,则应在类型前加const,以防止该指针在函数体内被意外修改。

[示例]

void StringCopy(char *strDestinationconst char *strSource);

[建议]:如果输入参数以值传递的方式传递对象,C++则宜改用“const &”方式来传递,这样可以省去临时对象的构造和析构过程,从而提高效率。

[内部规则]:如果输入参数以值传递的方式传递对象,C++则宜改用“const&”方式来传递,这样可以省去临时对象的构造和析构过程,从而提高效率。

[内部规则]:返回值为void类型的函数也要有return语句。


[规则]mallocnew申请内存之后,应该立即检查指针值是否为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,重要的是你必须为内存分配失败做好准备。

[建议]:在编写代码之前,应预先设计好程序调试与测试的方法和手段,并设计好各种调测开关及相应测试代码如打印函数等。

[内部规则]:在编写代码之前,应预先设计好程序调试与测试的方法和手段,并设计好各种调测开关及相应测试代码如打印函数等。






0 0
原创粉丝点击