Chapter 1. A Hypothetical Compiler
P7. "Enable all optional compiler warnings."
P8. "Use lint to catch bugs that your compiler may miss."
P9. "If you have unit tests, use them."
Chapter 2. Assert Yourself
P15. "Maintain both ship and debug versions of your program."
P19. "Use assertions to validate function arguments."
P21. "Strip undefined behavior from your code, or use assertions to catch illegal uses of undefined behavior."
P22. assert is "Not for Errors".
P23. "Don't waste people's time. Document unclear assertions."
P23. "ARE YOU MAKING ASSUMPTIONS AGAIN?“,逐步写出一个鲁棒性好的memset。
P27. "Either remove implicit assumptions, or assert that they are valid."
P27. "Owning the Compiler Is Not Enough",默认int是4字节而不用sizeof,曾经习以为常的居然这么危险!
P29. "Use assertions to detect impossible conditions."
P33. "Don't hide bugs when you program defensively."(defensive programming是指写的函数可以容忍传入的参数有误)
P38. "Use a second algorithm to validate your results."
P38. "Hey, What Goes On Here?"-->自定义宏时最好别调用函数
P42. "Don't wait for bugs to happen; use startup checks."(例如可以在接受数据结束后立即检查数据正确性)
P43. 题2有些意思。题3:注意assert是在debug用的。
Chapter 3. Fortify Your Subsystem
P49. Mac系统,malloc分配的空间可用0xA3填充。因为0xA3A3指令将导致系统crash。该页下面的代码值得一看。
P50. "Eliminate random behavior. Force bugs to be reproducible."
P54. 开头:"Debug versions don't have to be small and tight or have lightning fast response...Unless the code gets so big or so slow that programmers and testers sotp using it..."
P54. “Destroy your garbage so that it's not misused."
P58. Debug时,"If something happens rarely, force it to happen often."
P59. 介绍为申请的空间做记录,以便创建类似sizeofBlock和fValidPointer这些有很重要作用的函数。
P62. “Keep debug information to allow stronger error checking."
P67. "Create thorough subsystem checks, and use them often."
P68. "Design your tests carefully. Nothing should be arbitrary."
P68. "Strive to implement transparent integrity checks."让自己代码中的错误检查的意义清晰明了完整。
P70. ”Don't apply ship version constraints to the debug version. Trade size and speed for error detection."
Chapter 4. Step Through Your Code
P78. "Don't wait until you have a bug to step through your code."
P79. "Step through every code path."( if, switch, ...)
P81. "As you step through code, focus on data flow."
P83. "Turn Off Optimizations?"
P84. "Source level debuggers can hide execution details. Step through critical code at the instruction level."
Chapter 5. Candy-Machine Interface
P90. 这里批评了TCPL中所说的getchar返回值问题:C已属于高级语言,不用将两种值(返回值和字符)都放在返回值里。这样很容易造成程序员误操作:用char接受getchar()的返回值。作者推荐定义成flag fGetChar(char *pch);
P91. "Make it hard to ignore error confitions. Don't bury error codes in return values."
P92. realloc函数是另一个例子,返回值的代表多种意思,容易引诱程序员犯错。
P93. "Always look for, and eliminate, flaws in your interfaces."
P95. 分析了roalloc的奇葩所在:实际上它可以分开成4个函数——fNewMemory, FreeMemory, fGrowMemory, ShrinkMemory。
P95. “Don't wirte multipurpose functions. Write separate funtions to allow stronger argument validation."
P99. "Don't be wishy-washy(不清不楚). Define explicit function arguments."
P101. ”Write functions that, given valid inputs, cannot fail."
P104. "Make the code intelligible at the point of call. Avoid boolen arguments." 避免使用true,false,1,0,INT_MAX等指代特定含义但名字意义不明的东西,去用宏定义。比如#define UNREACHABLE 0。
P106. “Write comments that emphasize potential hazards."比如写函数说明时,可以附一个简单常用的例子。
P107. "Make it hard for programmers to unwrittingly ignore details;"
Chapter 6. Risky Busness
P114. ASCI:"Existing code are important."
P114. the spirit of C ---- Make it fast, even if it is not guaranteed to be portable.
P117. "Use well-defined data types." int,char等普通类型通常为了配合特定机器或系统而设计的,大小、有无符号等不能确定(但有不精确范围)。考虑使用unsigned char, signed int等。
P119. "Always ask, 'Can this variable or expression over- or underflow?' "
P121. "Implement your designs as accurately as possible. Being kinda close is being kingda buggy." 不需要把较多的设计放在一个函数里实现,应该适当分开,细化,让每个设计都简单明了。这里特别介绍intToStr函数遇到-32768(假设int是2Byte),该怎么处理:因为-32768取相反数后仍是-32768,所以这是要利用unsigned类型强制变化,然后再字符串化。
P124. "Implement 'the task' just once."尽量让一个任务一次实现,而不是分成很多if分别用不同路径实现。不能为了节约一点空间,让复杂度上升很多。给链表一个头节点就是个好方法(不用判断是否为NULL)。
P125. “...many times an if statement is the result of a sloppy implementation or design..."
P127. "Get rid of extraneous if statements."
P130. “Avoid using nested ?: operators" 容易使代码不清晰。用if...else代替,除非是a>b?a:b。
P131. "Handle your special cases just once." Sprinkle none of them throughout the code, so that other programmers won't miss them easyly.(最后这两个memchr版本居然有个厉害隐蔽的bug。)
P136. "Avoid risky language idioms." 加减等运算时刻警惕溢出,位运算,移位运算注意是否有符号(必要时类型转换一下)。
P142. 题2,不要将布尔值与TRUE比较。题3,避免古怪的设计。题4,最大限度增加公共代码减少差异。题8,除非确保数据有效,否则不要使用表格。题9,不要为了迁就差的编译器(优化能力不足)而去破坏代码清晰性(为了增加效率)。
Chapter 7. Treacheries of the Trade
P149. "Don't reference memory that you don't own." 小心并行程序,受保护空间,内存映射I/O,地址越界等。
P151. "Don't reference memory that you have freed."
P153. "Don't use output memory as workspace buffer." 可能带来奇怪的副作用。
P155. "...Never pass data in global buffers unless you absolutely have to."尤其在并行程序中。
P156. "Don't pass data in static (or global) memory."
P159. "Don't write parasitic(寄生的) functions." 一般来说,一个函数调用另一个函数,不应对被调用函数的实现方法有要求。即只是把它当接口,对其实现方式无依赖。
P160. "Don't abuse your programming language." For example, 别利用NULL定义为0这种细节,做些自认为小技巧的怪事。
P162. "A simple guideline is use || for logical expressions, use?: for conditional expressions, and use if for conditional statements."
P162. "Tight C does not guarantee efficient machine code." 代码不要写的过分紧凑。
P165. "Programmers frequently forget that they have two audiences: the customers who use the code and the maintenance programmers who have to update the code." 前者关于接口,后者关于代码风格等。
P165. "Write code for the 'average' programmer."
P170. 题8,9:避免随意的地址跳转。
Charpter 8. The Rest is Attitude
P173. "Bugs don't just 'go away'." 别偷懒,去找bugs突然消失的原因。
P175. "Don't fix bugs later; fix them now." 列出了4条理由。
P176. “Fix the cause, not the symptom." 治病治根。
P178. "Don't clean up code unless the cleanup is critical to the product's success."
P179. "Don't implement nonstrategic features."
P180. ”There are no free features." 别添加没意义的特性。
P181. "Don't allow unnecessary flexibility."
P183. "Don't keep 'trying' solutions until you find that works. Take the time to find the correct solution."
P185. "Write and test code in small chunks. Always test your code, even if that means your schedule will slip."
P187. "Don't rely on the tesing group to find your bugs." 程序员由里向外测试,测试员反之。
P188. "Don't blame testers for finding your bugs." Thank him.
P192. "Establish your priorities and stick to them." 这会让你不至于完全不懂以前的代码为何那样写。
Epilogue
P197. "Never allow the same bug to bite you twice." And keep asking yourself "Does this generate bugs?".
后记:
至此读完了这本好书。真是将我从以自己为中心的码农变为有大局观的。。。码农,不管如何思想上升了一个档次。
这本是特别推荐,所有程序员都该看的好书。就像打篮球一样,加入项目组后,自己的代码就不再是一个人的代码!
附录A是份作者列出的查BUG清单,写完一块代码该来这查查。