《代码阅读方法与实践》阅读笔记二

这些天阅读了本书的第二部分,以下是我的收获:

我们所观测到的不是自然本身,而是大自然在我们所用的观察方法下展现出来的特性。
代码阅读过程中可以使用的武器之一就是:用编译器对代码进行编译,检查产生的警告消息。
标准c、c++、Java程序从函数(Java中为方法)main开始执行。第一次分析一个程序时,main是一个好的起点。要注意,一些其他系统可能使用其他函数作为程序的入口点,例如WinMain或init。
在C/C++程序中,main函数的两个参数(通常命名为argc和argv用来将指定的命令行参数从操作系统传递到程序。Argc变量存储程序参数的个数,argv是一个字符串数组,包含所有的实参(包括程序自身的名称――位置0,即argv的第一个元素)。Argv数组由一个NULL元素结束。
Main函数的典型C/C++定义是:
int
main (int argc,char ** argv)
相应Java类方法的定义是:
Public static void main(String args[])
在比较两个字符串的相等性时,函数strcmp的返回值很不直观。当字符串相等时,它返回0,即C语言中的false。为此,很多C程序中会定义一个STREQ宏,使之在两个字符串相等时返回true,在这个宏中,常常通过立即比较前两个字符来优化比较过程。
#define STREQ(a,b) (*(a)==*(b)&&strcmp((a),(b))==0)
If-else if-…-else序列可以看作是由互斥选择项组成的选择结构。
使用未经初始化的变量是引发问题的一个常见原因。在检查代码时,一定要核实:是否所有的程序控制路径在使用变量前都恰当地对它们进行了初始化。一些编译器可以检测出部分此类错误,但是不应该依赖于这项功能。
Printf的返回值被转换成void类型。Printf返回实际打印出的字符数;向void类型的转换是想告诉我们这个结果被有意忽略。类似的,如果未能写出字符,putchar将返回EOF。所有输出函数――特别在程序的标准输出重定向到文件时――都有可能会由于各种各样的原因而失败。
不检查输出操作的结果可能会引起程序悄然失败,在没有任何警告的情况下丢失输出。检查所有输出操作的结果可能会很麻烦。一个实用的折衷办法是在程序结束前检查标准输出流上的错误。在java中,可以实用CheckError方法来完成这项工作。在C++程序中,可以实用流的fail,good或bad方法;在C代码中使用ferror函数:
If(ferror(stdout))
err(I,”stdout”);
在用一个新行结束了它的输出后,echo调用exit结束程序,用(0)表示成功。我们还会经常看到在main函数中返回0,这两种做法的结果相同。
2.2函数和全局变量
// expand程序将参数指定的文件(如果没有指定文件参数,则为标准输入)中硬制表符(\t ASCII字符9)展开成若干空格。默认的行为是每8个字符设置一个制表位;
在分析重要的程序时,最好首先识别出重要的组成部分。
函数前置声明:允许编译器检查传递给函数的参数,以及它们的返回值,相应地生成正确的代码。如果没有给出前置声明(forward declaration),C编译器将根据函数第一次使用时的情况对函数的返回值类型和参数作出假定;C++编译器将这种情况标记为错误。如果之后的函数定义与这些假定不相符,编译器将发出一条警告或错误消息。但是,如果定义于另一个文件中的一个函数满足这个错误的声明,则程序也许能够编译通过,但在运行时会失败。
// expand程序中,两个函数被声明为static,而变量并非static。这意味着,这两个函数只在该文件中可见,而变量则对组成程序的所有文件都是可见的。因此,在检查代码时,一个好的做法是确保所有只用于单一文件的变量都声明为static。(C)
要了解函数(或方法)的功用,可以使用下面的策略:
猜,基于函数名;阅读位于函数开始部分的注释;分析如何使用该函数;阅读函数体的代码;查阅外部的程序文档。
当基于猜测修改代码时,您应该设计能够验证最初设计的过程。这个过程可能包括用编译器进行检查、引入断言、或者执行适当的测试用例。
2.3while循环、条件和块
要养成遇到库元素就去阅读相关文档的习惯,这将增强我们阅读和编写代码的能力。
2.4switch语句
即使switch语句只处理一系列确定的值,也要尽量包括default标记,这是一个好的保护性编程习惯。这类default标记能够捕获产生意外值的编程错误,并能警告程序的维护人员。
2.5for循环
if((dd=opendir(dir))==NULL)
return (CC_ERROR);
for(dp=readdir(dd);dp!=NULL;dp=readdir(dd)){…..
对opendir的调用返回一个值,这个值可以传递给readdir,从而顺序地访问dir目录中的每个项。当该目录中没有更多的项时,readdir将返回NULL,循环也将结束。
无限循环:for(;;)。大多数情况下,无限循环用来表达在循环开始或结束时退出条件无法指定的循环。大这些循环一般不是通过return语句退出函数,就是通过break语句退出循环体,或者调用exit或类似的函数退出整个程序。C++,C#和Java程序还可以通过异常跳出这类循环。

你可能感兴趣的:(《代码阅读方法与实践》阅读笔记二)