《C陷阱与缺陷》之1词法"陷阱"
编译器中负责将程序分解为一个一个符号的部分,一般称为"词法分析器"。在C语言中,符号之间的空白(包括空格符、制表符或换行符)将被忽略。
1、=不同于==
C语言使用符号"="作为赋值运算符,符号"=="作为比较。赋值运算相对比较运算出现得更频繁,因此字符较少的符号"="就被赋予了更常用的含义——赋值操作。C语言中赋值符号被作为一种操作符对待,因而重复进行赋值操作可以很容易地书写,并且赋值操作还可以被嵌入到更大的表达式中。
这种使用上的便利性可能导致一个潜在的问题:当程序员本意是作为比较运算时,却可能无意中误写成了赋值运算。
if (x = y) break;
该句本意是要检查x是否等于y,而实际上是将y的值赋给了x,然后检查该值是否为零。
while(c = ' ' || c == '\t' || c == '\n') c = getc(f);
由于程序员在比较' '和变量c时误将比较运算符"=="写成了赋值运算符"="。因为赋值运算符"="优先级要低于逻辑运算符"||",因此实际上是将以下表达式的值赋给了c:
' ' || c == '\t' || c == '\n'
因为' '不等于0(ASCII值为32),那么无论变量c此前为何值,上述表达式求值的结果都是1,循环一直进行下去直到整个文件结束。
我们应该显式地进行比较,不应该简单关闭警告选项。
if (x = y) foo();
应该写作:
if ((x = y) == !0) foo();
如果把赋值运算符误写成比较运算符,同样会造成混淆:
if ((filedesc == open(argv[i], 0)) < 0) error();
因为比较运算表达式的值只有0或者1,因此(filedesc == open(argv[i], 0))的值永远只会是0或1,不可能<0而执行到error()函数。
2、&和|不同于&&和||
C语言中很容易将按位运算&与逻辑运算符&&,或者将按位或|与逻辑运算符||调换。
3、词法分析中的"贪心法"
C语言中的符号,例如"/"、"*"、"="只有一个字符长,称为单字符符号;例如"/*"、"=="以及标识符包含多个字符,称为多字符符号。当C编译器读入一个字符'/'后又跟了一个'*',那么编译器就必须作出判断:是将其作为2个分别的符号对待,还是合起来作为一个符号对待。C语言对这个问题的解决方案可以归纳成一个简单的规则:每一个符号应该包含尽可能多的字符。也就是说,编译器将程序分解成符号的方法是,从左到右一个字符一个字符读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的2个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号。这个处理策略叫做"贪心法"。
举例:
表达式a---b 与a -- - b含义相同,与a - -- b含义不同。
y = x/*p
本意是用x除以p所指向的值,把所得的商再赋给y;实际上,/*被编译器理解为一段注释的开始,编译器将不断读入字符,直到*/出现为止。
y = x / *p /* p指向除数 */
或者更加清楚一点,写作:
y = x/(*p)
这样得到的实际效果才是语句注释所表示的原意。
4、整型常量
如果一个整数常量的第一个字符是数字0,那么该常量将被视为八进制。因此,10和010的含义是截然不同。
5、字符与字符串
C语言中的单引号和双引号含义迥异,在某些情况下如果把2者弄混,编译器并不会检测报错,从而在运行时产生难以预料的结果。用单引号引起的一个字符实际代表一个整数;用双引号引起来的字符串代表的却是一个指向无名数组起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制为0的字符'\0'初始化。
例如:
char *slash = '\';
在编译时将会生成一个错误信息,因为'\'并不是一个字符指针。然而,某些C编译器对函数参数并不进行类型检查,特别是printf函数的参数。
《C陷阱与缺陷》之1词法"陷阱"的更多相关文章
- [C陷阱和缺陷] 第1章 词法“陷阱”
有感自己的C语言在有些地方存在误区,所以重新仔细把"C陷阱和缺陷"翻出来看看,并写下这篇博客,用于读书总结以及日后方便自身复习. 第1章 词法"陷阱" 1.1 ...
- 《C陷阱与缺陷》读书笔记
1. 词法“陷阱” = 不同于 == , 可以通过if( 1 == a )来避免 & | 不同于 && || 词法分析中的“贪心法” 编译器将程序分解成符号的方法是,从左到右一 ...
- 读书笔记--C陷阱与缺陷(一)
要参与C语言项目,于是作者只好重拾C语言(之前都是C++,还是C++方便). 看到大家都推荐看看 C陷阱与缺陷(C traps and pitfalls),于是好奇的开始了这本书的读书之旅. 决定将 ...
- C陷阱和缺陷学习笔记
这段时间把<C陷阱和缺陷>看了,没时间自己写总结.就转一下别人的学习笔记吧http://bbs.chinaunix.net/thread-749888-1-1.html Chapter 1 ...
- 《C陷阱与缺陷》阅读笔记(个人版)
笔记: 第一章:词法陷阱 提倡显示比较if((x = y) != 0) foo(); 第二章:语法陷阱 已知一个类型的声明 该类型的类型转换:吧声明中的变量名和声明末尾的分号去掉,再将剩余的部分用括号 ...
- 我的《C陷阱与缺陷》读书笔记
第一章 词法“陷阱” 1. =不同于== if(x = y) break; 实际上是将y赋给x,再检查x是否为0. 如果真的是这样预期,那么应该改为: if((x = y) != 0) break; ...
- 阅读《C陷阱与缺陷》的知识增量
版权声明:本文为Focustc原创文章.转载请注明作者及出处. https://blog.csdn.net/caozhankui/article/details/35925939 看完<C陷阱与 ...
- C语言学习书籍推荐《C陷阱与缺陷》下载
下载地址:点我 凯尼格 (作者), 高巍 (译者) <C和C++经典著作:C陷阱与缺陷>适合有一定经验的C程序员阅读学习,即便你是C编程高手,<C和C++经典著作:C陷阱与缺陷> ...
- 《C陷阱与缺陷》杂记
第一章 词法"陷阱" 1.4整型常量 如果一个整型常量的第一个字符是数字0,那么该常量将被视作八进制数.因此,10与010的含义截然不同.需要注意这种情况,有时候在上下文为了格式& ...
- C陷阱与缺陷(一)
第一章 词法陷阱 术语“符号”指的是程序的一个基本组成单元,其作用相当于一个句子中的单词.编译器中负责将程序分解为一个一个符号的部分,一般称为“词法分析器”. 1.1 =不同于== 一般容易将比较运算 ...
随机推荐
- Java --ClassLoader创建、加载class、卸载class
一.java提供了三种ClassLoader对Class进行加载: 1.BootStrap ClassLoader:称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库 ...
- 设置placeholder字体颜色
/*设置placeholder字体颜色*/::-webkit-input-placeholder{ color: #FFF;}:-ms-input-placeholder{ color: #FFF;} ...
- GJM : Python简单爬虫入门(二) [转载]
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- jshint配置(js检查)
JSHint的选项配置 asi 如果是真,JSHint会无视没有加分号的行尾,自动补全分号一直是Javascript很有争议的一个语法特性.默认,JSHint会要求你在每个语句后面加上分号,但是如果你 ...
- ASP.NET多文件上传实例
在Web应用程序开发中,避免不了要用到上传文件这个功能,但以前上传文件是个很麻烦的事,现在有了.NET,文件上传变得轻而易举.下面的这个例子实现了多文件上传功能.可以动态添加输入表单,上传的文件数量没 ...
- HTML 表单
HTML 表单包含表单元素. <form> 元素定义 HTML 表单 表单元素指的是不同类型的 input 元素.复选框.单选按钮.提交按钮等等. HTML 表单用于搜集不同类型的用户输入 ...
- HTML <base> 标签 为页面上的所有链接规定默认地址或默认目标
定义和用法 <base> 标签为页面上的所有链接规定默认地址或默认目标. 通常情况下,浏览器会从当前文档的 URL 中提取相应的元素来填写相对 URL 中的空白. 使用 <base& ...
- Python学习02 列表 List
Python学习02 列表 List Python列表 List Python中的列表(List)用逗号分隔,方括号包围(comma-separated values (items) between ...
- 使用Masonry搭建特殊布局时与xib的对比
之前只有比较浅的接触过Masonry.项目中大多数的布局还是用xib中的AutoLayout与手码的frame计算相结合,相信也会有很多项目和我一样是这两种布局的组合.其实xib各方面用的感觉都挺好, ...
- Swift - 访问通讯录-使用AddressBook.framework和AddressBookUI.framework框架实现
1,通讯录访问介绍 通讯录(或叫地址簿,电话簿)是一个数据库,里面储存了联系人的相关信息.要实现访问通讯录有如下两种方式: (1)AddressBook.framework框架 : 没有界面,通过代码 ...