Chinaunix首页 | 论坛 | 博客
  • 博客访问: 628680
  • 博文数量: 87
  • 博客积分: 3399
  • 博客等级: 中校
  • 技术积分: 1422
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-17 21:20
文章分类

全部博文(87)

文章存档

2013年(1)

2012年(51)

2011年(33)

2010年(2)

分类: C/C++

2012-02-13 13:27:33

                                         C陷阱与缺陷笔记

——C Traps and Pitfalls》(Addison-Wesley, 1989, ISBN 0-201-17928-8noted  by leo

2.13.2012

Andrew Koenig

AT&T贝尔实验室

Murray Hill ,新泽西07974

摘要

C语言就象一把雕刻用刀---简单 ,锋利,在熟手中极其有用。但象所有锋利的工具一样,C语言会伤害到那些不知驾驭的人。本文将展示C是如何伤害那些粗心的人,并将介绍如何避免这种伤害。

1. 词法陷阱
1.1  =  不是 = =
1.2  &| 不是 && ||
1.3  多字符的记号-词法分析中的贪心法

C的参考手册描述了如何进行判决:如果(编译器)输入流在截止到某个字符之前都已经被分解为一个个的符号,则下一个符号将包含从该字符之后可能组成一个符号的最长字符串。

a---b a-- -b的含义相同,而与a- --b的含义不同。

假如 /  是某个记号的第一个字符,且其后紧跟 *  ,则不管上下文如何,这两个字符都表示注释的开始,下面的表述看起来象是设定y的值为x除以指针p所指向的值:

y =  x/*p     /* p指向除数*/

实际上,由于/* 表示注释开始,编译器会简单的忽略代码直至*/的出现。换句话说,上面的表达式实际上仅仅将x的值赋给y ,甚至都没有引用p,如果后面没有*/则编译报错。

重写上述表达式为:

y = x/ *p;     /*p points to the divisor */ (注意:/*之间有空格隔开!)

或者:

y = x/(*p);        /* p points to the divisor*/

都会按照注释中的意思进行除法运算。

1.4   例外

复合赋值操作如 + = 是真正的多重记号。即,

    a + /* strange */ = 1;

表示的意思同以下:

    a + = 1;

这些操作符是唯一的,只有他们才可能看起来是单独的记号,而实际上却是多重记号。

leo VC6.0下并不能编译通过+ =

字符串和字符

C语言中的单引号和双引号的含义迥异,某些情况下如果弄混,编译器并不报错,从而产生难以预料的结果。

字符使用单引号,它只是整数的另一种写法。该整数的值为在字符集中与字符相应的序列值。因此,在ASCII序列中’a’表示0141或者97

字符串使用双引号,提供一种简洁的写法,将一个指针指向一个未命名的数组,该数组被初始化为双引号之间的字符和一个额外的二进制值为0的字符’\0’

printf("hello\n");

         char hello[] = {'h','e','l','l','o','\n',0}; //注意后面的0

         printf(hello);

         两者是等效的。

因为单引号括起的一个字符代表一个整数,而用双引号括起的一个字符代表一个指针,所以两者混用时,编译器的类型检查功能会检测到这样的错误。

char *slash = '/';

编译错误,’/’不是一个字符指针。

对于printf('\n');这样的错误,有的编译器保存,有的不报错。

因为整型数(一般16位或32位)通常都足够大,可以同时表示几个字符(一般8),所以有的 C 编译器允许字符常量(以及字符串常量)中有多个字符(若整数32位,字符8位,则单引号内可包含4个字符)。这表明当用‘yes’替代“yes”时可能不会被发现。后者表示四个分别装有yes\0字符的连续地址空间的首地址。前者表示一个由yes以某种方式定义的字符的整数。在这两个变量之间如果有相似之处都只是一种巧合。

Borland C++v5.5 LCC v3.6中,最后的整数值即第一个字符的整数值,VC6.0GCC v2.95中为最后一个字符的值。

a+++++b 编译报错,因为a++的值为右值,a++ ++ 是错误的,右值不可++

阅读(1719) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~