Chinaunix首页 | 论坛 | 博客
  • 博客访问: 384408
  • 博文数量: 82
  • 博客积分: 1855
  • 博客等级: 上尉
  • 技术积分: 846
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-12 12:28
文章存档

2013年(3)

2012年(8)

2011年(71)

分类: LINUX

2011-10-13 11:51:56

 

排版问题,参考附件

 附录一编程规范.doc   

排版

 

1.1.1  相对独立的程序块之间、变量声明之后必须加空行。

示例:

int          conn_fd;

int          ret;

    

conn_fd = socket(AF_INET, SOCK_STREAM,0);

if (conn_fd < 0) {

    perror("socket create");

}

1.1.2  程序块要采用缩进风格编写,缩进为4个空格或一个Tab键。

如上个示例中,perror缩进了一个Tab键,这样可以增加程序的可读性。

1.1.3  对于较长的语句(超过个80字符)要分成多行书写,划分出的新行要进行适当的缩进,使排版整齐,语句可读。对于参数较长的函数也要划分成多行。

示例:

ret = connect(conn_fd, (struct sockaddr *)&serv_addr,

                  sizeof (struct sockaddr));

1.1.4  一行只写一条语句,不允许把多个短语句写在一行中。

示例:

以下语句是不规范的:

min_port = 1;   max_port = 65535;

应该如下书写:

min_port = 1;  

max_port = 65535;

1.1.5  iffordowhilecaseswitchdefault等语句各自占一行,且iffordowhile等语句的执行语句部分无论多少都要加括号{ }

以下语句是不规范的:

if (conn_fd < 0) perror("socket create");

应该如下书写:

if (conn_fd < 0) {

     perror("socket create");

}

1.1.6  函数内的语句、结构的定义、循环和if语句中的代码都要采用缩进风格,case语句后的处理语句也要缩进。

示例:

typedef struct _port_segment {

     struct in_addr      dest_ip;    // struct相对于typedef缩进4个字符

     unsigned short int  min_port;

     unsigned short int  max_port;

} port_segment;

 

if (conn_fd < 0) {

     perror("socket create"); // perror缩进4个字符

}

 

for (i=portinfo.min_port; i<=portinfo.max_port; i++) {

      serv_addr.sin_port = htons(i);  // serve_addr.sin_port缩进4个字符

...

1.1.7  程序块的两个分界符(C语言中为‘{’和‘}’)应独占一行并且位于同一列。或者‘{’位于上一行的行末,此时‘}’与‘{’所在行的行首对齐,‘{’前至少有一个空格。

以下代码中‘{’和‘}’各自占一行,且位于同一列:

for (i=1; i

{

     ...

}

或者在代码中‘{’与for语句同行,‘{’与其前面的‘}’有一个空格,‘}’与‘{’语句所在行的行首对齐:

for (i=1; i

     ...

}

1.1.8  空格的使用

1)以下语句在逗号后面加空格。

     int min_port, max_port;

2"+""-""*""="等算术运算符两边都有一个空格。

     a = i + j;

3"<"">="等比较操作符两边都有一个空格。

     if (conn_fd < 0) {

4"!""""++""--""&"(地址运算符)等单目操作符前后不加空格。

     i++;

5"->""."前后不加空格。

     portinfo.min_port = i * seg_len + 1;

6ifforwhileswitch等与后面的括号间应加空格,以便使iffor等关键字更为突出和明显。

     if (conn_fd < 0)

 

注释

 

1.2.1  注释的原则是有助于对程序的阅读和理解,注释不宜太多也不能太少。注释语言必须准确、易懂、简洁,没有歧义性。

1.2.2  程序文件(如以.h结尾的头文件、以.c结尾的源程序文件)头部代码应进行注释。注释必须列出:版权说明、版本号、生成日期、作者、内容、功能、与其他文件的关系、修改日志等。头文件的注释中还应有函数功能简要说明。

示例。

/*

* Copyright(C), 2007-2008, Red Hat Inc. // 版权声明

* File name:                            // 文件名

* Author:            // 作者

* Version:               // 版本

* Date:             // 完成日期

* Description:      // 描述本文件的功能,与其他模块的关系

* Function List:        // 主要函数的列表,每条记录应包括函数名及功能简要说明

* History:           // 修改历史,包括每次修改的日期、修改者和修改内容简述

*/

1.2.3  函数头部应进行注释,列出函数的功能、输入参数、输出参数、返回值、调用关系等。

示例:

/*

* Function:     // 函数名称

* Description:       // 函数功能、性能等的描述

  * Calls:        // 被本函数调用的函数清单

* Called By:     // 调用本函数的函数清单

* Input:           // 输入参数说明,包括每个参数的作用

* Output:        // 输出参数说明,有时通过指针参数返回一些变量值

* Return:         // 函数返回值的说明

* Others:        // 其他说明

*/

1.2.4  边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。无用的注释要及时删除。

1.2.5  注释应该在相应的代码附近,对代码的注释应放在其上方或右方(对单条语句的注释),不可放在下面,若放于上方则需与其上面的代码用空行隔开。

1.2.6  对于所有有特定含义的变量、常量、宏、结构体等数据结构,如果其命名不是充分自注释的,在声明时都必须加上注释,说明其实际含义。变量、常量、宏的注释应放在其上方或右方。

1.2.7  全局变量要有较详细的注释,包括功能,取值范围,哪些函数访问它,访问时的注意事项。

1.2.8  为使程序排版整齐,方便阅读和理解,注释也要进行缩进和对齐。

示例:

void example_function( void )

{

     /* comments one */

     unsigned int min_port, max_port;

         

     /* comments two */

     if ...

}

1.2.9  对关键变量的定义、条件分支、循环语句必须写注释。这些语句往往是程序实现某一特定功能的关键代码,良好的注释能帮助理解程序,有时甚至优于看设计文档。

1.2.10  避免在一行代码的中间插入注释。

以下方式的注释应该避免:

max_port  /* 只扫描11024的常用端口 */ = 1024;

1.2.11  对于含义非常明确的变量、数据结构、语句,不必加上注释。

1.2.12  在复杂程序块的结束行右方加注释,以表明某程序块的结束。

示例:

if (...)

{

    ...

    

    while ( ... )

    {

     ...

    } /* while ( ... )循环语句结束*/

     ...

    

} /* end of  if (...)语句结束 */

 

标识符、变量、宏

 

1.3.1  对于标识符的命名,要有自己的风格,一旦形成不可随意变更,除非团队项目开发中要求使用统一的风格。

1.3.2  标识符的命名要清晰明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。

示例:

temp可以简写为tmp

message可以简写为msg

1.3.3  对于变量命名,禁止使用单个字符(如ijk),建议除了要有具体含义外,还能表明其数据类型等,但ijk作为局部循环变量是允许的。

示例:

int iwidth; // i表明该变量为int型,width指明是宽度

1.3.4  命名规范必须与所使用的系统风格保持一致,如在Linux下变量命名一般是全小写加下划线的风格。

一般使用:

int min_port;

一般不使用:

int minPort;

1.3.5  除了头文件或结构体定义,应避免使用_ourhead_h_之类以下划线开始和结尾的定义。

以下是允许的:

#ifndef  _ourhead_h_

#define _ourhead_h_

...

#endif

 

typedef struct _port_segment {

     struct in_addr          dest_ip;    

     unsigned short int     min_port;

     unsigned short int     max_port;

} port_segment;

1.3.6  注意运算符的优先级,并用括号明确表达式的操作顺序。

示例:

if ((a | b) < (c & d))

1.3.7  避免使用不易理解的数字,用有意义的标识来替代。对于常量,不应直接使用数字,必须用有意义的枚举或宏来代替。

示例:

#define BUFF_SIZE          1024

input_data = (char *)malloc(BUFF_SIZE);

而应避免出现类似以下的代码:

p = (char *)malloc(1024);

1.3.8  不要使用难懂的技巧性很高的语句,除非很有必要时。

示例:

不应出现类似以下的代码:

count ++ += 1;

而应改为:

count  += 1;

count++;

3.91.3.9  尽量避免使用全局变量,全局变量增大了模块间的耦合性,不利于软件维护。

1.3.10  使用全局变量时,应明确其含义、作用、取值范围。明确全局变量与操作此变量的函数的关系,如创建、访问、修改。

1.3.11  在多线程程序中使用全局变量,应注意对变量操作的原子性。

1.3.12  应避免局部变量与全局变量同名。

1.3.13  严禁使用未经初始化的变量作为右值。在C程序中,引用未经赋值的指针,经常会引起程序崩溃。

以下代码在Linux下将导致错误,原因在于:没有使p_string指向某个内存空间的情况下,即对其进行操作是错误的。

char *p_string;

p_sting[0] = ‘a’;

应先进行初始化:

char *p_string;

p_string = (char *)malloc(BUFF_SIZE);          // 这里假设BUFF_SIZE已定义

p_sting[0] = ‘a’;    

1.3.14  用宏定义表达式时,要使用完备的括号。

如下定义的宏存在一定的风险:

#define GET_AREA(a,b)     a*b

应该定义为:

#define GET_AREA(a,b)     ((a*b))

1.3.15  若宏中有多条语句,应该将这些语句放在一对大括号中。

下面语句中只有宏的第一条表达式被执行。

#define INTI_RECT_VALUE( a, b )\

    a = 0;\

    b = 0;

for (index = 0; index < RECT_TOTAL_NUM; index++)

             INTI_RECT_VALUE( rect.a, rect.b );

正确的用法应为:

#define INTI_RECT_VALUE( a, b ) {\

            a = 0;\

            b = 0;\

}

for (index = 0; index < RECT_TOTAL_NUM; index++) {

          INTI_RECT_VALUE( rect[index].a, rect[index].b );

}

 

函数

 

1.4.1  一个函数完成一个特定的功能,不应尝试在一个函数中实现多个不相关的功能。

1.4.2  检查函数所有输入参数的有效性,比如指针型参数要判断是否为空,数组成员参数判断是否越界。

1.4.3  一个函数的规模应限制在200行以内(不包括空行和注释行)。

1.4.4  函数的功能应该是可以预测的,也就是只要输入数据相同就应产生同样的预期输出。

1.4.5  函数的参数不宜过多,以13个为宜。

1.4.6  函数名应准确描述函数的功能,一般以动词加宾语的形式命名。

示例。

void print_record( struct *p_record, int record_len) ;

1.4.7  函数的返回值要清楚、明了,让使用者不容易忽视错误情况。函数的每种出错返回值的意义要清晰、明确,防止使用者误用,理解错误或忽视错误返回码。

1.4.8  如果多段代码重复做同一件事情,那么应该考虑把重复功能实现为一个函数。

1.4.9  减少函数本身或函数间的递归调用。

递归调用特别是函数间的递归调用(如A->B->C->A),影响程序的可理解性;递归调用一般都占用较多的系统资源(如栈空间);递归调用对程序的测试不利。

1.4.10  编写函数时应注意提高函数的独立性,尽量减少与其他函数的联系;提高代码可读性、可维护性和效率。

 

程序效率

 

1.5.1  编程时要经常注意代码的效率。

代码效率分为全局效率、局部效率、时间效率及空间效率。全局效率是站在整个系统角度上的效率;局部效率是站在模块或函数角度上的效率;时间效率是程序处理输入任务所需的时间长短;空间效率是程序所需内存空间,如机器代码空间大小、数据空间大小、栈空间大小等。

1.5.2  在保证软件系统的正确性、稳定性、可读性及可维护性的前提下,提高代码效率。

不能一味地追求代码效率,而对软件的正确性、稳定性、可读性及可维护性造成损害。

1.5.3  通过对数据结构的划分与组织的改进,以及对程序算法的优化来提高空间效率。

1.5.4  循环体内的工作量应最小化。

如下代码效率不高:

for (ind = 0; ind < MAX_ADD_NUMBER; ind++) {

         sum += ind;

    back_sum = sum; /* backup sum */

}

语句“back_sum = sum;”完全可以放在for语句之后,如下:

for (ind = 0; ind < MAX_ADD_NUMBER; ind++) {

      sum += ind;

}

back_sum = sum; /* backup sum */

1.5.5  要仔细地构造或直接用汇编编写调用频繁或性能要求极高的函数。

1.5.6  在保证程序质量的前提下,通过压缩代码量,去掉不必要代码以及减少不必要的局部和全局变量,来提高空间效率。

1.5.7  在多重循环中,应将最忙的循环放在最内层,以减少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];

    }

}

1.5.8  避免循环体内含判断语句,应将循环语句置于判断语句的代码块之中。

如下代码效率较低:

     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;

              }

     }

 

代码质量和代码安全

 

1.6.1  代码质量和代码安全包含以下内容:代码的正确性(实现预期的功能)、稳定性、安全性、可测试性、可维护性、可读性和效率。

1.6.2  防止引用已经释放的内存空间。

在实际编程过程中,稍不留心就会出现在一个模块中释放了某个内存块,而另一模块在随后的某个时刻又引用了它,要防止这种情况发生。

1.6.3  函数中分配的内存,在函数结束前要释放。

1.6.4  防止内存操作越界。

内存操作主要是指对数组、指针、内存地址等的操作。内存操作越界是软件系统主要的错误之一,后果是使运行中的程序崩溃,或者留下安全漏洞。

以下代码对array[10]进行了操作,导致数组越界访问:

int array[10], i;

for(i = 1; i <=10; i++) {

     array[i] = 10;

}

对于类似的错误,编译器不能检测出,认为合法。

1.6.5  处理程序可能遇到的各种出错情况。

例如,打开一个文件时要考虑文件是否存在,是否有权限访问等。

1.6.6  系统运行之初,要初始化有关变量及运行环境,防止未经初始化的变量被引用。

1.6.7  程序编写完成后,应该检查易混淆的操作符,如“==”和“=”、“&&”和“&”、“||”和“|”。

1.6.8  Linux下,多线程中的子线程退出必须采用主动退出方式,即子线程应在return处结束运行。

1.6.9  尽量避免使用goto语句。goto语句会破坏程序的结构性,除非确实需要。

1.6.10  注意表达式是否会上溢、下溢。

示例:

unsigned char size = 5;

while (size-- >= 0)      // 将出现下溢

{

         ... // 程序代码

}

size等于0时,再减1值为-1。系统中-1表示为0xFF255也表示为0xFF,由于size为无符号数,系统认为该值为255,故程序是一个死循环。

应作如下修改:

char size;      // unsigned char 改为char

while (size-- >= 0)

{

    ... // 程序代码

}

1.6.11  系统应具有一定的容错能力,对一些错误事件(如用户误操作)能进行自动补救。

 

阅读(1538) | 评论(0) | 转发(0) |
0

上一篇:GNU Make基础

下一篇:Linux和Windows相互访问

给主人留下些什么吧!~~