好记性不如烂笔头o(^▽^)o
C语言的艺术之函数
- C语言的艺术之函数
- 11个函数仅完成1件功能
- 2重复代码应当尽量提炼成函数
- 3避免函数太长新增函数尽可能不超过50行非空非注释行
- 4避免函数的代码块嵌套过深新增函数的代码块嵌套不超过4层
- 5可重入函数应避免使用同享变量若需要使用则应通过互斥手段关中断信号量对其加以保护
- 6对参数的合法性检查由调用者负责还是由接口函数负责应在项目组模块内应统1规定缺省由调用者负责
- 7对函数的毛病返回码要全面处理
- 8设计高扇入公道扇出小于7的函数
- 9废弃代码没有被调用的函数和变量要及时清除
- 10函数不变参数使用const
- 11函数应避免使用全局变量静态局部变量和IO操作不可避免的地方应集中使用
- 12检查函数所有非参数输入的有效性如数据文件公共变量等
- 13函数的参数个数不超过5个
- 14除打印类函数外不要使用可变长参函数
- 15在源文件范围内声明和定义的所有函数除非外部可见否则应当增加static关键字
1、1个函数仅完成1件功能
1个函数实现多个功能给开发、使用、保护都带来很大的困难。
将没有关联或关联很弱的语句放到同1函数中,会致使函数职责不明确,难以理解,难以测试和改动。
案例:realloc
在标准C语言中,realloc是1个典型的不良设计。这个函数基本功能是重新分配内存,但它承当了太多的其他任务:如果传入的指针参数为NULL就分配内存,如果传入的大小参数为0就释放内存,如果可行则就地重新分配,如果不行则移到其他地方分配。如果没有足够可用的内存用来完成重新分配(扩大原来的内存块或分配新的内存块),则返回NULL,而原来的内存块保持不变。这个函数不容易扩大,容易致使问题。例以下面代码容易致使内存泄漏:
char *buffer = (char *)malloc(XXX_SIZE);
.....
buffer = (char *)realloc(buffer,NEW_SIZE);
如果没有足够可用的内存用来完成重新分配,函数返回为NULL,致使buffer原来指向的内存被丢失。
2、重复代码应当尽量提炼成函数
项目组应当使用代码重复度检查工具,在延续集成环境中延续检查代码重复度指标变化趋势,并对新增重复代码及时重构。当1段代码重复两次时,即应斟酌消除重复,当代码重复超过3次时,应当立刻着手消除重复。
1般情况下,可以通过提炼函数的情势消除重复代码。
3、避免函数太长,新增函数尽可能不超过50行(非空非注释行)
太长的函数常常意味着函数功能不单1,过于复杂。
函数的有效代码行数,即NBNC(非空非注释行)应当在[1,50]区间。
业界普遍认为1个函数的代码行不要超过1个屏幕,避免来回翻页影响浏览。
例外:某些实现算法的函数,由于算法的聚合性与功能的全面性,可能会超过50行。
4、避免函数的代码块嵌套过深,新增函数的代码块嵌套不超过4层
函数的代码块嵌套深度指的是函数中的代码控制块(例如:if、for、while、switch等)之间相互包括的深度。每级嵌套都会增加浏览代码时的脑力消耗,由于需要在头脑里保护1个“栈”(比如,进入条件语句、进入循环……)。应当做进1步的功能分解,从而避免使代码的浏览者1次记住太多的上下文。优秀代码参考值:[1,4]。
5、可重入函数应避免使用同享变量;若需要使用,则应通过互斥手段(关中断、信号量)对其加以保护
可重入函数是指可能被多个任务并发调用的函数。在多任务操作系统中,函数具有可重入性是多个任务可以共用此函数的必要条件。同享变量指的全局变量和static变量。
编写C语言的可重入函数时,不应使用static局部变量,否则必须经过特殊处理,才能使函数具有可重入性。
示例:函数square_exam返回g_exam平方值。那末以下函数不具有可重入性。
int g_exam;
unsigned int example( int para )
{
unsigned int temp;
g_exam = para; // (**)
temp = square_exam ( );
return temp;
}
此函数若被多个线程调用的话,其结果多是未知的,由于当(**)语句刚履行完后,另外1个使用本函数的线程可能正好被激活,那末当新激活的线程履行到此函数时,将使g_exam赋于另外一个不同的para值,所以当控制重新回到“temp =square_exam ( )”后,计算出的temp极可能不是料想中的结果。此函数应以下改进。
int g_exam;
unsigned int example( int para )
{
unsigned int temp;
[申请信号量操作] // 若申请不到“信号量”,说明另外的进程正处于
g_exam = para; //给g_exam赋值并计算其平方进程中(即正在使用此
temp = square_exam( ); // 信号),本进程必须等待其释放信号后,才可继
[释放信号量操作] // 续履行。其它线程必须等待本线程释放信号量后
// 才能再使用本信号。
return temp;
}
6、对参数的合法性检查,由调用者负责还是由接口函数负责,应在项目组/模块内应统1规定。缺省由调用者负责
对模块间接口函数的参数的合法性检查这1问题,常常有两个极端现象,即:要末是调用者和被调用者对参数均不作合法性检查,结果就遗漏了合法性检查这1必要的处理进程,造成问题隐患;要末就是调用者和被调用者均对参数进行合法性检查,这类情况虽不会造成问题,但产生了冗余代码,下降了效力。
7、对函数的毛病返回码要全面处理
1个函数(标准库中的函数/第3方库函数/用户定义的函数)能够提供1些唆使毛病产生的方法。这可以通过使用毛病标记、特殊的返回数据或其他手段,不管甚么时候函数提供了这样的机制,调用程序应当在函数返回时立刻检查毛病唆使。
8、设计高扇入,公道扇出(小于7)的函数
扇出过大,表明函数过分复杂,需要控制和调和过量的下级函数;而扇出太小,例如:总是1,表明函数的调用层次可能过量,这样不利于程序浏览和函数结构的分析,并且程序运行时会对系统资源如堆栈空间等造成压力。通常函数比较公道的扇出(调度函数除外)通常是3~5。
扇出太大,1般是由于缺少中间层次,可适当增加中间层次的函数。扇出太小,可把下级函数进1步分解多个函数,或合并到上级函数中。固然分解或合并函数时,不能改变要实现的功能,也不能背背函数间的独立性。
扇入越大,表明使用此函数的上级函数越多,这样的函数使用效力高,但不能背背函数间的独立性而单纯地寻求高扇入。公共模块中的函数及底层函数应当有较高的扇入。
较良好的软件结构通常是顶层函数的扇出较高,中层函数的扇出较少,而底层函数则扇入到公共模块中。
9、废弃代码(没有被调用的函数和变量)要及时清除
说明:程序中的废弃代码不但占用额外的空间,而且还常常影响程序的功能与性能,极可能给程序的测试、保护等造成没必要要的麻烦。
10、函数不变参数使用const
11、函数应避免使用全局变量、静态局部变量和I/O操作,不可避免的地方应集中使用
带有内部“存储器”的函数的功能多是不可预测的,由于它的输出可能取决于内部存储器(如某标记)的状态。这样的函数既不容易于理解又不利于测试和保护。在C语言中,函数的static局部变量是函数的内部存储器,有可能使函数的功能不可预测。
12、检查函数所有非参数输入的有效性,如数据文件、公共变量等
函数的输入主要有两种:1种是参数输入;另外一种是全局变量、数据文件的输入,即非参数输入。函数在使用输入参数之前,应进行有效性检查。
13、函数的参数个数不超过5个
函数的参数过量,会使得该函数易于受外部(其他部份的代码)变化的影响,从而影响保护工作。函数的参数过量同时也会增大测试的工作量。
函数的参数个数不要超过5个,如果超过了建议拆分为不同函数。
14、除打印类函数外,不要使用可变长参函数
15、在源文件范围内声明和定义的所有函数,除非外部可见,否则应当增加static关键字
如果1个函数只是在同1文件中的其他地方调用,那末就用static声明。使用static确保只是在声明它的文件中是可见的,并且避免了和其他文件或库中的相同标识符产生混淆的可能性。
建议定义1个STATIC宏,在调试阶段,将STATIC定义为static,版本发布时,改成空,以便于后续的打热补钉等操作。
#ifdef _DEBUG
#define STATIC static
#else
#define STATIC
#endif
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。