http://www.cnblogs.com/soroman/archive/2007/08/06/845465.html
读书笔记:Writing Solid Code (2):
http://www.cnblogs.com/soroman/archive/2007/12/22/1010870.html
读书笔记:Writing Solid Code (3):
http://www.cnblogs.com/soroman/archive/2007/12/25/1014142.html
Go on writting solid code...
-----------------------------------
Chapter 6 Risky Business
危险的事情
-----------------------------------
Summary:
Given the numerous implementation possibilities for a given function, it
should come as no surprise that some implementations will be more errorprone
than others. The key to writing robust functions is to exchange risky
algorithms and language idioms for alternatives that have proven to be
comparably efficient yet much safer. At one extreme this can mean using
unambiguous data types; at the other it can mean tossing out an entire design
simply because it would be difficult, or impossible, to test.
概述:
如果一个函数有很多实现方案的可能,那么一定是其中一些实现比另一些出错的可能性更大。实现稳定的函数的关键是不用带风险的算法和语言习惯,而是去用那些同样高效但是很安全的方案。在一个极端下,这意味着使用无歧义的数据类型,在另一个极端下,这意味着必须扔掉全部的设计,仅仅是因为它是很难或者不可能被测试的。
Guidlines:
6.1.Use well-defined data types.
使用定义明确的数据类型。
【注】当ANSI委员会看到C运行在各种平台上,它们看到C不是一个象用户认为的那样的一个portable的语言。并仅仅是因为C标准库在不同的系
统上不一样,还因为预处理器和语言本身。ANSI标准委员会对大部分方面作了标准化,但是却忽略了基本数据类型。ANSI没有具体的定义int,char,long,而是留下具体实现给编译器厂商。结果,有些ANSI标准的编译器支持32位整型和带符号的字符型,另外一些编译器可能支持16位整型和无符号char型。
那么看看下面的代码:
1
char ch;
2
ch = 0xFF;
3
if (ch == 0xFF)
4
}
2
3
4
上面的判断到底是true or false,你永远也不知道,因为这依赖于编译器的实现。如果是无符号char型,那么结果是true,如果是带符号char型,那么结果就是false。还有象类似:int reg = 3;虽然reg被定义成int,reg可以是signed或者unsigned,还是取决于你的编译器。你必须使用signed int或者unsigned int。
short是多大?int呢?long呢?ANSI标准并没有说,而是留给编译器的作者去决定。标准没有规定的原因是考虑到兼容以前的代码。
6.2.Always ask, "Can this variable or expression over- or underflow?"
时刻问自己:”这个变量或者表达式溢出了吗?”
【注】看看下面的代码:
1
}
这段代码的问题在于ch=UCHARMAX的时候,再加1,会导致等于0,所以造成死循环。上面是Overflow的问题,同样存在Underflow的问题:
1
void *memchr(void *pv, unsigned char ch, size_t size)
2
}
2
如果size是unsigned的话,当size=0后再进行递减操作的话,那么就会翻转成unsigned型的size_t的最大值。好消息是如果你按照我在第四章所建议的那样去检查的话,你就可以发现这些溢出bugs。
6.3.Implement "the task" just once.
只实现“任务”一次。
【注】设想为了表示一个文档处理程序中的层次状的Window结构,设计如下结构体:
1
typedef struct WINDOW
2
*/
2
现在表示所有的Window可以由该结构体节点构成的二叉树来表示,注意其中的Root节点实际上只有成员pwndChild是有意义的--指向所有top-level的windows, 因为没有兄弟姐妹和Title,而且Root是不能move,hide,or delete的,所以有人将Root节点简化成其中一个成员,即用指针pwndRootChildren来表示,这样至少可以减少空间。于是AddChild(添加一个子window到已存在的window节点下)的实现如下: 1