当前位置:文档之家› 卓越的教练是如何训练高手的?周立功新浪博客

卓越的教练是如何训练高手的?周立功新浪博客

节目预告

当年明月

小学班长,请进。推敲你的例题百年一人

美国人眼中最不道德的事儿是啥乔磊

解释“中国”之难

但斌

大学生创业:爱心比资金更重要快活林

《告诉孩子怎样爱》:让他们不林艺

20091226唐师曾:北大校长周其peaceduck唐老鸭

日本人的沉默螺旋

毛丹青

夫妻之间的生活趣事大曝光

龙谈

[组图]最新让人暴汗的囧人囧图娄行健

也就是说我们需要将结构体指针强制转换成char * 才能够正常工作,这样除了字符串以外其它的类型都不可避免地要进行指针强制转换,否则编译器就会呱呱叫,比如在VC++2008下就会出现这样的错误:

error C2664: 'MyMemMove' : cannot convert parameter 1 from 'TheStruct *' to 'char *'

那么如何解决这个问题呢?其实很简单,我们知道有一种特别的指针,任何类型的指针都可以对它赋值,那就是void *,所以应该将源地址和目的地址都用void*来表示。当然函数体的内容也要作相应的改变,这样我们就得到了V0.2版的程序。

程序清单 3 V0.2版程序

void MyMemMove(void *dst,void *src,int count)

{

while (count--)

{

*(char *)dst = *(char *)src;

dst = (char *)dst + 1;

src = (char *)src + 1;

}

}

有的同学可能会问,这里面不是还有指针强制转换吗?只不过是换了地方。没错,强制指针转换确实是从使用者的代码转移到了库的代码里,但我们可以将MyMemMove理解为库,而将Test理解为使用者,事实上通过调整之后的效果却有天壤之别,V0.1是一逸永劳,而V0.2是一劳永逸!

还有几个细节需要注意,为了实现链式表达式,我们应该将返回值也改为void *。此外,如果我们不小心

将“*(char *)dst = *(char *)src;”写反了,写成“*(char *)src = *(char *)dst;”编译照样通过,而为了找出这个错误又得花费不少时间。注意到src所指向的内容在这个函数内不应该被改变,所有对src所指的内容赋值都应该被禁止,所以这个参数应该用const修饰,如果有类似的错误在编译时就能够被发现:

error C3892: 'src' : you cannot assign to a variable that is const

作为程序员犯错误在所难免,但是我们可以利用相对难犯错误的机器,也就是编译器来降低犯错误的概率,这样我们就得到了V0.3版的程序。

程序清单 4 V0.3版程序

void * MyMemMove(void *dst,const void *src,int count)

{

void *ret=dst;

while (count--)

{

*(char *)dst = *(char *)src;

dst = (char *)dst + 1;

src = (char *)src + 1;

}

return ret;

}

现在再来考虑这样一种情况,有使用者这样调用库:MyMemMove(NULL,src, count),这是完全可能的,因为一般来说这些地址都是程序计算出来的,那就难免会算错,出现零地址或者其它的非法地址也不足为奇。可以预料的是,如果出现这种情况的话,则程序马上就会down掉,更糟糕的是你不知道错误出在哪里,于是不得不投入大量的精力在浩瀚的代码中寻找bug。解决这类问题的通用办法是对输入参数作合法性检查,也就是V0.4版程序。

5 V0.4版程序

void * MyMemMove(void *dst,const void *src,int count) {

void *ret=dst;

if (NULL==dst||NULL ==src)

{

return dst;

}

while (count--)

{

*(char *)dst = *(char *)src;

分享到新浪微博圈

)

周老师,你好,在这提问不知是否合适,我把

插入表情发评论

相关主题
文本预览
相关文档 最新文档