文档库 最新最全的文档下载
当前位置:文档库 › c语言初学者编程规范函数与过程

c语言初学者编程规范函数与过程

c语言初学者编程规范函数与过程
c语言初学者编程规范函数与过程

C语言初学者编程规范—函数与过程

1 函数的功能与规模设计(1)函数应当短而精美,而且只做一件事。不要设计多用途面面俱到的函数,多功能集于一身的函数,很可能使函数的理解、测试、维护等变得困难。一个函数应最多占满1或2个屏幕(就象我们知道的那样,ISO/ANSI的屏幕大小是80X24),只做一件事并且把它做好。一个函数的最大长度与它的复杂度和缩进级别成反比。所以,如果如果你有一个概念上简单(案,“简单”是simple而不是easy)的函数,它恰恰包含着一个很长的case语句,这样你不得不为不同的情况准备不懂的处理,那么这样的长函数是没问题的。然而,如果你有一个复杂的函数,你猜想一个并非天才的高一学生可能看不懂得这个函数,你就应当努力把它减缩得更接近前面提到的最大函数长度限制。可以使用一些辅助函数,给它们取描述性的名字(如果你认为这些辅助函数的调用是性能关键的,可以让编译器把它们内联进来,这比在单个函数内完成所有的事情通常要好些)。

对函数还存在另一个测量标准:局部变量的数目。这不该超过5到10个,否则你可能会弄错。应当重新考虑这个函数,把它分解成小片。人类的大脑一般能同时记住7个不同的东西,超过这个数目就会犯糊涂。或许你认为自己很聪明,那

么请你理解一下从现在开始的2周时间你都做什么了。(2)为简单功能编写函数。虽然为仅用一两行就可完成的功能去编函数好象没有必要,但用函数可使功能明确化,增加程序可读性,亦可方便维护、测试。示例:如下语句的功能不很明显。value = ( a > b ) ? a : b ;改为如下就很清晰了。

int max (int a, int b)

{

return ((a > b) ? a : b);

}value = max (a, b);或改为如下。

#define MAX (a, b) (((a) > (b)) ? (a) : (b))

value = MAX (a, b);当一个过程(函数)中对较长变量(一般是结构的成员)有较多引用时,可以用一个意义相当的宏代替——这样可以增加编程效率和程序的可读性。示例:在某过程中较多引用TheReceiveBuffer[FirstSocket].byDataPtr,则可以通过以下宏定义来代替:# define pSOCKDATA TheReceiveBuffer[FirstScoket].byDataPtr(3)防止把没有关

联的语句放到一个函数中,防止函数或过程内出现随机内聚。随机内聚是指将没有关联或关联很弱的语句放到同一个函

数或过程中。随机内聚给函数或过程的维护、测试及以后的升级等造成了不便,同时也使函数或过程的功能不明确。使用随机内聚函数,常常容易出现在一种应用场合需要改进此函数,而另一种应用场合又不允许这种改进,从而陷入困境。在编程时,经常遇到在不同函数中使用相同的代码,许多开发人员都愿把这些代码提出来,并构成一个新函数。若这些代码关联较大并且是完成一个功能的,那么这种构造是合理的,否则这种构造将产生随机内聚的函数。

示例:如下函数就是一种随机内聚。

void Init_Var( void )

{

Rect.length = 0;

Rect.width = 0; /* 初始化矩形的长与宽*/

Point.x = 10;

Point.y = 10; /* 初始化“点”的坐标*/

}

矩形的长、宽与点的坐标基本没有任何关系,故以上函数是随机内聚。应如下分为两个函数:

void Init_Rect( void )

{

Rect.length = 0;

Rect.width = 0; /* 初始化矩形的长与宽*/

}void Init_Point( void )

{

Point.x = 10;

Point.y = 10; /* 初始化“点”的坐标*/

}(4)如果多段代码重复做同一件事情,那么在函数的划分上可能存在问题。若此段代码各语句之间有实质性关联并且是完成同一件功能的,那么可考虑把此段代码构造成一个新的函数。(5)减少函数本身或函数间的递归调用。递归调用特别是函数间的递归调用(如A->B->C->A),影响程序的可理解性;递归调用一般都占用较多的系统资源(如栈空间);递归调用对程序的测试有一定影响。故除非为某些算法或功能的实现方便,应减少没必要的递归调用,对于safe-related 系统不能用递归,因为超出堆栈空间很危险。

2 函数的返回值(1)对于函数的返回位置,尽量保持单一性,即一个函数尽量做到只有一个返回位置。(单入口单出口)。要求大家统一函数的返回值,所有的函数的返回值都将以编码的方式返回。

例如编码定义如下:

#define CM_POINT_IS_NULL CMMAKEHR(0X200)

:

:

建议函数实现如下:

LONG 函数名(参数,……)

{

LONG lResult; //保持错误号lResult=CM_OK;

//如果参数有错误则返回错误号if(参数==NULL)

{

lResult=CM_POINT_IS_NULL; goto END;

}

……

END:

return lResult;

}(2)除非必要,最好不要把与函数返回值类型不同的变量,以编译系统默认的转换方式或强制的转换方式作为返回值

返回。(3)函数的返回值要清楚、明了,让使用者不容易忽视错误情况。函数的每种出错返回值的意义要清晰、明了、准确,防止使用者误用、理解错误或忽视错误返回码。(4)函数的功能应该是可以预测的,也就是只要输入数据相同就应产生同样的输出。带有内部“存储器”的函数的功能可能是不可预测的,因为它的输出可能取决于内部存储器(如某标记)的状态。这样的函数既不易于理解又不利于测试和维护。在

C/C++语言中,函数的static局部变量是函数的内部存储器,有可能使函数的功能不可预测,然而,当某函数的返回值为指针类型时,则必须是STATIC的局部变量的地址作为返回值,若为AUTO类,则返回为错针。示例:如下函数,其返

回值(即功能)是不可预测的。

unsigned int integer_sum( unsigned int base )

{

unsigned int index;

static unsigned int sum = 0; // 注意,是static类型的。

// 若改为auto类型,则函数即变为可预测。

for (index = 1; index <= base; index++)

{

sum += index;

}

return sum;

}

3 函数参数(1)只当你确实需要时才用全局变量,函数间应尽可能使用参数、返回值传递消息。(2)防止将函数的参数作为工作变量。将函数的参数作为工作变量,有可能错误地改变参数内容,所以很危险。对必须改变的参数,最好先用局部变量代之,最后再将该局部变量的内容赋给该参数。

示例:下函数的实现不太好。

void sum_data( unsigned int num, int *data, int *sum )

{

unsigned int count;

*sum = 0;for (count = 0; count < num; count++)

{

*sum += data[count]; // sum成了工作变量,不太好。

}

}若改为如下,则更好些。

void sum_data( unsigned int num, int *data, int *sum ) {

unsigned int count ;

int sum_temp;

sum_temp = 0;for (count = 0; count < num; count ++) {

sum_temp += data[count];

}*sum = sum_temp;

}

相关文档