C陷阱与缺陷:第五,六章

第五章    库函数

1. getchar() 的返回值

char c;

while ((c = getchar()) !=  EOF)

    putchar (c);

上面代码运行错误的原因是将c定义为char类型,而getchar()返回的是int类型值 。EOF 是一个宏,标准规定它的值必须是一个 int 型的负数常量。通常编译器都会把 EOF 定义为 -1。问题就出在,使用 char 型变量接收 getchar 等函数的返回值会导致对 EOF 的辨认出错,它有可能把正确的数据误认为是 EOF,或者把 EOF 误认为是正确的数据。解决这个问题的方法是,将变量c定义为int型。

以上参考:http://www.wscxy.com/shosh/article.asp?id=13

 

2.

以下第二个fseek函数发改变了文件的状态,使得文件可以正常读取:

FILE *fp;

struct record  rec;

… …

while (fread((char *) &rec, sizeof(rec), 1, fp)  == 1)

{

    // 对rec执行某些操作

   if (//必须被重新写入)

   {

       fseek (fp, –(long)sizeof(rec), 1);

       fwrite ((char *)&rec, sizeof(rec),  1, fp);

       fseek (fp, 0l, 1);

    }

}

一个输入操作不能随后直接紧跟一个输出操作,反之亦然。如果要同时输入和输出操作,必须在其中插入fseek函数的调用。

 

3. 缓冲输出与内存分配

下面代码中的setbuf()函数将不能正常运行:

main()

{

    int c;

    char buf[BUFSIE];

    setbuf(stdout, buf);

 

    while ((c = getchar()) != EOF)

        putchar(c);

}

原因是setbuf()的第二个参数中的数组变量buf在main结束后,将释放内存空间。但是,程序程序交回给操作系统之前要做缓冲区的清理工作,但此时的buf已被释放。解决这一问题的两个策略是:

1). 将数组变量声明为全局的,用static修饰,或是将声明放到main()外面;

2). 将数组声明为动态内存,这样不会主动释放内存空间。

 

 

第6章    预处理器

1. 宏定义中的空格

#define f (x)  ((x) - 1)    // f(x) 代表 (x)  ((x) - 1)

如果要将f(x)定义代表为((x) - 1),则应写为:

#define f(x) ((x) - 1)

 

2. 宏不是函数

在宏定义时,最好把宏定义中的每个参数都用圆括号括起来。但有时即使在表达式处加有圆括号,但仍有可能存在问题,原因是参数定义有副作用。解决这一问题的方式是,宏定义的参数没有副作用,或是不要用宏定义来现实,而是用函数现实。

 

另外一个危险是,宏展开可能产生非常宏大的表达式。

 

3. 宏不是语句

当宏定义利用if语句来定义时,宏定义中的语句不会加分号,但在调用宏时,会在语句后加一个分号。这样就有可能将if的判断忽略掉。这解这一问题的办法是,在调用宏定义时后面不加分号。

 

4. 宏不是类型定义

宏的一个主要优点是——可移植性!但是它不是类型,与typedef定义类型上有区别,如:

#define T1 struct foo *

typedef struct foo *T2;

T1 a, b;    // a是结构的指针,b是结构,而不是指针

T2 a, b;   // a, b都是结构的指针

posted @ 2010-11-02 23:16  jeff_nie  阅读(274)  评论(0编辑  收藏  举报