编程之规范(四)
2012-12-08 00:17
204 查看
转自http://blog.sina.com.cn/s/blog_5e8facd20100eorv.html
工业级程序要出现了,顶住看下去。
到目前为止,在语言层面上,我们的程序基本上没有什么问题了,那么是否真的就没有问题了呢?
这就要求程序员从逻辑上考虑了,这也是优秀程序员必须具备的素质,那就是思维的严谨性,否则
程序就会有非常隐藏的bug,就这个例子来说,如果用户用下面的代码来调用你的程序。
程序清单 8 重叠的内存测试
如果你身边有电脑,你可以试一下,你会发现输出并不是我们期待的“hhello,world!”(在“hello
world!”前加个h),而是“hhhhhhhhhhhhhh”,这是什么原因呢?原因出在源地址区间和目的地址
区间有重叠的地方,V0.6版的程序无意之中将源地址区间的内容修改了!有些反映快的同学马上会说我
从高地址开始拷贝。粗略地看,似乎能解决这个问题,虽然区间是重叠了,但是在修改以前已经拷贝了
,所以不影响结果。但是仔细一想,这其实是犯了和上面一样的思维不严谨的错误,因为用户这样调用
还是会出错:
所以最完美的解决方案还是判断源地址和目的地址的大小,才决定到底是从高地址开始拷贝还是低地址
开始拷贝,所以V0.7顺利成章地出来了。
程序清单 9 V0.7版程序
经过以上7个版本的修改,我们的程序终于可以算是“工业级”了。回头再来看看前面的测试用例,
就会发现那根本就算不上是测试用例,因为它只调用了最正常的一种情况,根本达不到测试的目的。
有了上面的经历,测试用例也就相应地出现了,我们不妨用字符数组来模拟内存。
程序清单 10 相对全面的测试用例
初写代码的时候,往往考虑的是程序正常工作的情况该怎么处理。当你有了几年经验,写了几万行代码后就会发现,处理异常部分的分支代码有时比正常的主干线代码还要多,而这也正是高质量程序和一般程序拉开差距的地方。如果把软件产品当作一台机器,那么这样一个个细小的函数和类就是零部件,只有当这些零部件质量都很高时,整个软件产品的质量才会高,不然就会像前几年的国产轿车一样,今天这个零件罢工明天那个零件休息。而作为检验这些零部件的测试用例,一定要模拟各种恶劣的环境,将零部件隐藏的缺陷暴露出来,从这意义上说,编写测试用例的程序员要比软件设计的程序员思维要更严谨才行。
工业级程序要出现了,顶住看下去。
到目前为止,在语言层面上,我们的程序基本上没有什么问题了,那么是否真的就没有问题了呢?
这就要求程序员从逻辑上考虑了,这也是优秀程序员必须具备的素质,那就是思维的严谨性,否则
程序就会有非常隐藏的bug,就这个例子来说,如果用户用下面的代码来调用你的程序。
程序清单 8 重叠的内存测试
void Test() { char p [256]= "hello,world!"; MyMemMove(p+1,p,strlen(p)+1); printf("%s\n",p); }
如果你身边有电脑,你可以试一下,你会发现输出并不是我们期待的“hhello,world!”(在“hello
world!”前加个h),而是“hhhhhhhhhhhhhh”,这是什么原因呢?原因出在源地址区间和目的地址
区间有重叠的地方,V0.6版的程序无意之中将源地址区间的内容修改了!有些反映快的同学马上会说我
从高地址开始拷贝。粗略地看,似乎能解决这个问题,虽然区间是重叠了,但是在修改以前已经拷贝了
,所以不影响结果。但是仔细一想,这其实是犯了和上面一样的思维不严谨的错误,因为用户这样调用
还是会出错:
MyMemMove( p, p+1, strlen(p)+1);
所以最完美的解决方案还是判断源地址和目的地址的大小,才决定到底是从高地址开始拷贝还是低地址
开始拷贝,所以V0.7顺利成章地出来了。
程序清单 9 V0.7版程序
void * MyMemMove(void *dst,const void *src,int count) { void * ret = dst; assert(dst); assert(src); if (dst <= src || (char *)dst >= ((char *)src + count)) { while (count--) { *(char *)dst = *(char *)src; dst = (char *)dst + 1; src = (char *)src + 1; } } else { dst = (char *)dst + count - 1; src = (char *)src + count - 1; while (count--) { *(char *)dst = *(char *)src; dst = (char *)dst - 1; src = (char *)src - 1; } } return(ret); }
经过以上7个版本的修改,我们的程序终于可以算是“工业级”了。回头再来看看前面的测试用例,
就会发现那根本就算不上是测试用例,因为它只调用了最正常的一种情况,根本达不到测试的目的。
有了上面的经历,测试用例也就相应地出现了,我们不妨用字符数组来模拟内存。
程序清单 10 相对全面的测试用例
void Test() { char p1[256] = "hello,world!"; char p2[256] = {0}; MyMemMove(p2,p1,strlen(p1)+1); printf("%s\n",p2); MyMemMove(NULL,p1,strlen(p1)+1); MyMemMove(p2,NULL,strlen(p1)+1); MyMemMove(p1+1,p1,strlen(p1)+1); printf("%s\n",p1); MyMemMove(p1,p1+1,strlen(p1)+1); printf("%s\n",p1); }
初写代码的时候,往往考虑的是程序正常工作的情况该怎么处理。当你有了几年经验,写了几万行代码后就会发现,处理异常部分的分支代码有时比正常的主干线代码还要多,而这也正是高质量程序和一般程序拉开差距的地方。如果把软件产品当作一台机器,那么这样一个个细小的函数和类就是零部件,只有当这些零部件质量都很高时,整个软件产品的质量才会高,不然就会像前几年的国产轿车一样,今天这个零件罢工明天那个零件休息。而作为检验这些零部件的测试用例,一定要模拟各种恶劣的环境,将零部件隐藏的缺陷暴露出来,从这意义上说,编写测试用例的程序员要比软件设计的程序员思维要更严谨才行。
相关文章推荐
- 华为软件编程规范和范例
- Android支持Java语言语法编程 尚未承诺遵守规范
- C# 编码规范和编程好习惯
- Object-C 声明属性为什么用下划线,代码规范和编程风格
- Javascript模块化编程(二):AMD规范
- Android 开发应该注意的编程规范
- 20条学习javascript的编程规范的建议
- Java本地接口(JNI)编程指南和规范(第十章)
- C语言编程规范2: 排版
- C#编程规范
- 单片机开发之C语言编程基本规范
- C语言之程序编程规范
- [C/C++/嵌入式]嵌入式C编程的风格规范
- 三种编程命名规范
- 我的编程之路(二十一) 规范
- 【数据库】编程规范与安全
- 华为C语言编程规范(3)—注释
- 第三章 高质量C编程规范命名规则
- Javascript模块化编程系列三: CommonJS & AMD 模块化规范描述
- Javascript模块化编程(二):AMD规范