C语言缺陷与陷阱.doc

C语言缺陷与陷阱.doc

ID:56277825

大小:103.00 KB

页数:21页

时间:2020-06-05

C语言缺陷与陷阱.doc_第1页
C语言缺陷与陷阱.doc_第2页
C语言缺陷与陷阱.doc_第3页
C语言缺陷与陷阱.doc_第4页
C语言缺陷与陷阱.doc_第5页
资源描述:

《C语言缺陷与陷阱.doc》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库

1、C语言缺陷与陷阱(笔记)C语言像一把雕刻刀,锋利,并且在技师手中非常有用。和任何锋利的工具一样,C会伤到那些不能掌握它的人。本文介绍C语言伤害粗心的人的方法,以及如何避免伤害。第一部分研究了当程序被划分为记号时会发生的问题。第二部分继续研究了当程序的记号被编译器组合为声明、表达式和语句时会出现的问题。第三部分研究了由多个部分组成、分别编译并绑定到一起的C程序。第四部分处理了概念上的误解:当一个程序具体执行时会发生的事情。第五部分研究了我们的程序和它们所使用的常用库之间的关系。在第六部分中,我们注意到了

2、我们所写的程序也许并不是我们所运行的程序;预处理器将首先运行。最后,第七部分讨论了可移植性问题:一个能在一个实现中运行的程序无法在另一个实现中运行的原因。词法分析器(lexicalanalyzer):检查组成程序的字符序列,并将它们划分为记号(token)一个记号是一个由一个或多个字符构成的序列,它在语言被编译时具有一个(相关地)统一的意义。C程序被两次划分为记号,首先是预处理器读取程序,它必须对程序进行记号划分以发现标识宏的标识符。通过对每个宏进行求值来替换宏调用,最后,经过宏替换的程序又被汇集成字

3、符流送给编译器。编译器再第二次将这个流划分为记号。1.1=不是==:C语言则是用=表示赋值而用==表示比较。这是因为赋值的频率要高于比较,因此为其分配更短的符号。C还将赋值视为一个运算符,因此可以很容易地写出多重赋值(如a=b=c),并且可以将赋值嵌入到一个大的表达式中。1.2&和

4、不是&&和

5、

6、1.3多字符记号C语言参考手册说明了如何决定:“如果输入流到一个给定的字符串为止已经被识别为记号,则应该包含下一个字符以组成能够构成记号的最长的字符串”“最长子串原则”1.4例外   组合赋值运算符如+=实际

7、上是两个记号。因此,a+/*strange*/=1和a+=1是一个意思。看起来像一个单独的记号而实际上是多个记号的只有这一个特例。特别地,p->a是不合法的。它和p->a不是同义词。另一方面,有些老式编译器还是将=+视为一个单独的记号并且和+=是同义词。1.5字符串和字符包围在单引号中的一个字符只是编写整数的另一种方法。这个整数是给定的字符在实现的对照序列中的一个对应的值。而一个包围在双引号中的字符串,只是编写一个有双引号之间的字符和一个附加的二进制值为零的字符所初始化的一个无名数组的指针的一种简短方

8、法。使用一个指针来代替一个整数通常会得到一个警告消息(反之亦然),使用双引号来代替单引号也会得到一个警告消息(反之亦然)。但对于不检查参数类型的编译器却除外。由于一个整数通常足够大,以至于能够放下多个字符,一些C编译器允许在一个字符常量中存放多个字符。这意味着用'yes'代替"yes"将不会被发现。后者意味着“分别包含y、e、s和一个空字符的四个连续存储器区域中的第一个的地址”,而前者意味着“在一些实现定义的样式中表示由字符y、e、s联合构成的一个整数”。这两者之间的任何一致性都纯属巧合。2句法缺陷理

9、解这些记号是如何构成声明、表达式、语句和程序的。2.1理解声明每个C变量声明都具有两个部分:一个类型和一组具有特定格式的、期望用来对该类型求值的表达式。float*g(),(*h)();表示*g()和(*h)()都是float表达式。由于()比*绑定得更紧密,*g()和*(g())表示同样的东西:g是一个返回指float指针的函数,而h是一个指向返回float的函数的指针。当我们知道如何声明一个给定类型的变量以后,就能够很容易地写出一个类型的模型(cast):只要删除变量名和分号并将所有的东西包围在一

10、对圆括号中即可。float*g();声明g是一个返回float指针的函数,所以(float*())就是它的模型。(*(void(*)())0)();硬件会调用地址为0处的子程序(*0)();但这样并不行,因为*运算符要求必须有一个指针作为它的操作数。另外,这个操作数必须是一个指向函数的指针,以保证*的结果可以被调用。需要将0转换为一个可以描述“指向一个返回void的函数的指针”的类型。(Void(*)())0在这里,我们解决这个问题时没有使用typedef声明。通过使用它,我们可以更清晰地解决这个问题

11、:typedefvoid(*funcptr)();//typedeffuncptrvoid(*)();指向返回void的函数的指针(*(funcptr)0)();//调用地址为0处的子程序2.2运算符并不总是具有你所想象的优先级绑定得最紧密的运算符并不是真正的运算符:下标、函数调用和结构选择。这些都与左边相关联。接下来是一元运算符。它们具有真正的运算符中的最高优先级。由于函数调用比一元运算符绑定得更紧密,你必须写(*p)()来调用p指向的函数;*p()表

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。