灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2538回复:0

C陷阱与缺陷代码分析之第1章词法陷阱

楼主#
更多 发布于:2013-07-17 13:26
编译器中负责将程序分解为一个一个符号的部分,称为“词法分析器”。下面看一个例子:
 
if(x > big) big = x;
 
这个语句的第一个符号是C语言的关键字if,紧接着下一个符号是左括号,再下一个符号是标识符x,再下一个是大于号,再下一个是标识符big,依次类推。在C语言中,符号之间的空白符将被忽略。
 
本章将探讨符号和组成符号的字符间的关系,以及有关符号含义的一些常见误解。
 
 
 
陷阱1 “=”不同于“==”
 
将相等符号”==”误写为赋值符号”=”,是一种容易出现的错误,而且不容易检查出来。来看一个示例程序page6_7.c,其代码如下:
 
[cpp]
 1#include <stdio.h>  
 2  
 3int main()  
 4{  
 5    int i, j;  
 6    i = 10;  
 7    j = 20;  
 8    if(i = j)  
 9        printf("i equal j\n");  
10  
11    return 0;  
12}  
 
 1#include <stdio.h>
 2
 3int main()
 4{
 5    int i, j;
 6    i = 10;
 7    j = 20;
 8    if(i = j)
 9        printf("i equal j\n");
10
11    return 0;
12}
编译运行效果如下:
 


 
本程序第8行,本意是判断i是否等于j,如果相等则打印语句。现在将”==”误写为”=”,语意变成将j的值赋值给i,然后if判断i的值是否为0。所以,除非j的值为0,否则第8行的if判断总是为真。做为验证,可以试试下面的程序运行效果:
 
[cpp]
1#include <stdio.h>  
 2  
 3int main()  
 4{  
 5    int i, j;  
 6    i = 10;  
 7    j = 0;  
 8    if(i = j)  
 9        printf("i equal j\n");  
10  
11    return 0;  
12}  
 
 1#include <stdio.h>
 2
 3int main()
 4{
 5    int i, j;
 6    i = 10;
 7    j = 0;
 8    if(i = j)
 9        printf("i equal j\n");
10
11    return 0;
12}
 
 
 
陷阱2 词法分析中的“贪心法”
 
C语言中的某些符号,例如/、*、和=,只有一个字符长,称为单字符符号,还有一些符号,例如/*和==,包含多个字符,称为多字符符号。当C编译器读入一个字符”/”后又读入一个字符”*”,那么编译器就必须做出判断:是将其作为两个单字符符号对待还是合起来作为一个字符对待。
 
C语言对这个问题的解决方案是采用“贪心法”(又称“大嘴法”):每个符号应该包含尽可能多的字符。
 
看例子page8_9.c,代码如下:
 
[cpp]
1#include <stdio.h>  
2  
3int main()  
4{  
5    int a = 10, b=2;  
6    printf("a = 10, b = 2, a---b = %d\n", a---b);  
7  
8    return 0;  
9}  
 
1#include <stdio.h>
2
3int main()
4{
5    int a = 10, b=2;
6    printf("a = 10, b = 2, a---b = %d\n", a---b);
7
8    return 0;
9}
编译执行结果如下:
 


 
第6行,a---b按照贪心法分析,等价于(a--) - b,特别需要注意前面是a--,即先取a的值,再做减1操作,所以10 - 2 =
8。没运行之前,我认为结果应该是7呢。
 
 
 
陷阱3 整型常量
 
如果一个整型常量的第一个字符是数字0,那么该常量将被视作八进制数,因此,11和011的含义截然不同。
 
看代码page10_11.c:
 
[cpp]
1#include <stdio.h>  
2  
3int main()  
4{  
5    int a = 11, b = 011;  
6    printf("a = %d, b = %d\n", a, b);  
7  
8    return 0;  
9}  
 
1#include <stdio.h>
2
3int main()
4{
5    int a = 11, b = 011;
6    printf("a = %d, b = %d\n", a, b);
7
8    return 0;
9}编译执行结果如下:

 
由执行结果可以看出,011被看作是八进制数,对应的十进制数是9。
 
 
 
陷阱4 字符与字符串
 
C语言中的单引号与双引号含义迥异,在某些情况下,如果把两者弄混,编译时会出错,有时编译器不报错,从而在运行时产生难以预料的结果。
 
用单引号括起来的一个字符实际上代表一个整数,整数值对应于该字符在编译器采用的字符集中的序列值。因此,对于采用ASCII字符集的编译器而言,’a’的含义与0141(八进制)或者97(十进制)严格一致。
 
用双引号括起来的字符串,代表的却是一个指向无名数组起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制值为0的字符’\0’初始化。
 
下面这个语句:
 
printf(“Hello world\n”);
 

 
char hello[] = {‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘ ‘, ‘w’, ‘o’, ‘r’, ‘l’, ‘d’,
‘\n’, 0};
 
printf(hello);
 
是等效的。

喜欢0 评分0
游客

返回顶部