如何写一个高质量的函数

来源:互联网 发布:mactex Mac 百度云 编辑:程序博客网 时间:2024/06/05 11:44

如何写一个高质量的函数

 错误处理在写一个可靠的系统程序里是一个非常关键的问题。当你在写一个函数时,请想到这个函数可能会被同一个应用程序进行无数次的调用。那么你想让这个函数的行为是什么样的呢?通常,当有错误发生时,函数不能自己肆意退出,而应该告诉调用者出现了什么样的错误,这样做就使调用者有机会去修复错误或者是以一种很完善的方式退出程序。

 

函数也不能以返回值之外的形式对进程状态产生一些非预期的改变。比如,当一个函数阻塞了一个信号,在函数返回之前必恢复到进入这个函数之前的状态。

 

最后,这个函数应该释放所有它执行时所新占用的资源。如果一个函数调用malloc分配了一段临时内存并且在返回之前没有释放。如果只调用少数几次可能看不出什么问题,但当你进行了很多次的调用后就会让进程的内存资源使用超过限制,从而让你的程序濒临蹦溃。通常,如果一个函数分配了内存,要么在返回之前释入新申请的内存,要么要返回新申请的内存的指针给调用方,否则就会出现内存泄漏。内存泄漏是指内存已经在系统的控制之外在进程被终止之前不能再被使用。

 

你同样还需注意到,当一个库函数调用失败时通常并不会使你的程序退出。但是,当程序继续运行时,常用处于一种不稳定的状态或是使用一些非常的数据。所以你必须检查每一个库函数的返回值,对每一个错误的返回都进行适当的处理。

 

你自己写的函数同样必须十分注意错误处理。UNIX程序的标准错误处理方法如下:


.打印出错误消息并且退出程序(这条只针对main)
.返回-1或是NULL,并且设置一个错误指示,比如:errno
.返回一个错误码

 

通常,函数应该永不自己自行退出,而应该告诉调用方出现了什么错误。函数内部的错误消息可能在debug阶段非常的有用,但在最终的版本里通常不应出现这些信息。一个好的处理debug状态的方法是,你得有一个机制可以动态改变程序的消息打印状态。

 

例子2.10
下面的代码段示意了怎样在函数里对错误消息使用条件编译的选项。
   
#define DEBUG    /* comment this line out for no error messages */

int myfun(int x)
{
    x++;
#ifdef DEBUG
       fprintf(stderr, "The current value of x is %d/n", x);
#endif
}

当你注释掉#define这一行,那么fprintf这个语句将不会编译进最终的可执行程序myfun函数也不会进行打印。同样,你也可以把#define完全放到代码的外面,只在编译的命令行中添加DEGUG宏如下:

 

cc -DDEBUG ...

 

注:本人觉得日志打印有更好的选择方式,可以对消息分级别,程序运行的时候可以动态修改这个打印级别,这样程序重新编译不需要,也不需要打断现有程序的执行。

 

许多的库函数为写一个函数提供了一个很好的模型。下面是一些指导性原则:


1. 确保函数的返回值返回有用的信息给调用方,并且可以很方便的侦测错误。
2.  函数内部不要随意退出程序。而是要返回一个错误值,并且可以让调用方很方便的处理这个错误.
3.  尽量使函通用且可用(很多时候这两个目标是冲突的)
4.  不要对buffers的大小做任何的假定。
5.  当需要使用一些限定值时,使用标准的system-defined限定而不直接使用一个常量。
6.  不要自己重新搞无用的发明——尽可能的使用标准的库函数。
7.  不要修改输入参数的值,除非有这样做的意义。
8.  如果自动变量同样可以工作得很好的话,不要使用静态变量或是动态分配内存。
9.  分析所有的malloc类函数,确保程序对所有动态分配的内存都进行了合适的处理。
10. 必须注意是否有函数递归调用了,或是在信号处理里调用了,或是在线程里. 如果这个函数有静态变量就可能产生非预期的情况。比如(strtok对线程)。
11. 分析所在操作被信号中断的情况
12. 仔细的分析一个完整的程序是如何终止的。

原创粉丝点击