读书人

一对孪生子函数的疯狂PK。

发布时间: 2013-07-01 12:33:04 作者: rapoo

一对双胞胎函数的疯狂PK。。。
本帖最后由 tianwaixing2007 于 2013-05-21 22:01:28 编辑 近日工作中偶遇关于一个函数实现的争论,大家意见并不一致,两种实现风格如下:


int test1()
{
char*a=NULL;
char*b=NULL;
char*c=NULL;
char*d=NULL;
a=(char*)malloc(8);
if(!a)
goto out;
b=(char*)malloc(8);
if(!b)
goto out;
c=(char*)malloc(8);
if(!c)
goto out;
d=(char*)malloc(8);
if(!d)
goto out;
printf("test\r\n");
out:
if(d) free(d);
if(c) free(c);
if(b) free(b);
if(a) free(a);
return 0;
}



int test2()
{
char*a;
char*b;
char*c;
char*d;
a=(char*)malloc(8);
if(!a)
goto out0;
b=(char*)malloc(8);
if(!b)
goto out1;
c=(char*)malloc(8);
if(!c)
goto out2;
d=(char*)malloc(8);
if(!d)
goto out3;
printf("test\r\n");
out3:
if(d) free(d);
out2:
if(c) free(c);
out1:
if(b) free(b);
out0:
if(a) free(a);
return 0;
}


关于这两个函数的优劣,大家尽可畅所欲言。从代码风格、易读性、执行效率、潜在风险等方面予以评价,说说您对两种实现的看法。
先抛砖引玉,个人觉得test2()的实现更优。
C malloc printf 风格 效率
[解决办法]
个人认为第一个好些,编译了一下第一个用了0.8秒,第二个0.9秒。
[解决办法]
当然是test2()的实现更优啦.显然两段代码的可读性是等同的,但是如果这段代码的调用很频繁而且调用次数很多,那么使用test2()能够避免很多不必要的条件判断.所以它的效率远远高于test1().但是从另一方面讲,许多编译器都能在编译时对代码进行优化,所以可能两个函数经过编译器的编译后产生的中间代码几乎是一样的.从而使它们的执行效率相同,但是我们不能过分依赖编译器.我们要尽可能写出更优秀的程序,才能不断提高自己的编程能力.时间有限,我就简短的说这些了,说的不好,望楼主海涵...
[解决办法]
效率应该是第二个好一点。。可读性第一个更好。。不过第二种的效率优势基本可以忽略不计,所以我还是选第一种。。
[解决办法]
当然要集中释放……
第二种可读性差(多了3个标签,而且流程复杂了很多),可维护性差(如果以后要添加一个指针变量或者减少一个指针变量需要改动较多代码),相对而言获得的效率提升完全可以忽略,哪怕是最苛刻的效率要求也可以忽略,仅仅多执行了若干次判断;


[解决办法]
第一点:指针变量赋初值NULL是一个良好的编程习惯,不管在哪个实现中都应该赋初值;
第二点:x会怎么被意外修改?举例说明?

引用:
对于1和2的比较,我觉得1的缺点有两点:
1.test1会增加几个变量的赋值
2.test1中会有不必要的if(x) free(x)的执行,而这种执行会因为x的被意外修改而导致潜在风险

[解决办法]
int test1()
{
char* a=(char*)malloc(8);
char* b=(char*)malloc(8);
char* c=(char*)malloc(8);
char* d=(char*)malloc(8);

if(a && b && c && d)
geto Err;

printf("test\r\n");
Err:
free(d);//根本不用考虑太多 malloc的返回值都可以free 哪怕是一个NULL 也没问题
free(c);
free(b);
free(a);
return 0;
}

[解决办法]
引用:
Quote: 引用:

个人喜好第一种,但第一种也需要做修改,直接free(x),x是可以为null的
第二种效率上是稍微高了那么一点点,但可以完全无视,这点效率的优化完全忽略掉吧。但缺点却是十分明显的,加入现在在abcd基础上要加一个成员变量e或者删除一个,是不是很麻烦。
追求极致的程序运行效率性能是值得肯定的,但实际项目中还是多考虑可读性和可维护性。
不喜欢用goto,我会这么写
int test2()                                                                                                                           
{
char *a = NULL;
char *b = NULL;
char *c = NULL;
char *d = NULL;

do {
a = (char *)malloc(8);
if (!a)
break;
b = (char *)malloc(8);
if (!b)
break;
c= (char *)malloc(8);
if (!c)
break;
d = (char *)malloc(8);
if (!d)
break;
return 0;
} while(0);

free(a);
free(b);
free(c);
free(d);
return -1;
}

可以看linux下驱动开发,一般初始化部分都是采用类似2的做法,基本就是我在14楼写的例子那样,goto并不是不能用,有些时候用goto更直观

您说的很对。
现在两种方法风格都在用,写模块驱动为和系统和同事保持一致,我用第二种;
自己写应用程序时还是尽量没有用goto语句(有些地方用goto还是十分有必要和漂亮的),可能是个人简单习惯爱好。




另:
21楼tianwaixing2007
free前判断下不失为好的方法。牺牲极小的效率换来代码(不限于博主的这里代码)的简单整洁和方便维护还是值得权衡比较一下的。
[解决办法]

//如果分配空间的总大小可以预先计算出来,我会这么写
int test1()
{
char*a=NULL;
char*b=NULL;
char*c=NULL;
char*d=NULL;
a=(char*)malloc(8*4);
if(!a)
{
return -1;
}
b=a+8;
c=a+16;
d=a+24;
printf("test\r\n");
free(a);
return 0;
}

读书人网 >C语言

热点推荐