目录
第一章:词法陷阱
1.1 = 不同于 ==
- =在C语言中是赋值操作符,==在C语言中是比较运算符
1.2 & 和 | 不同于 && 和 ||
- &在C语言中是取地址操作符或按位与操作符、|在C语言中是按位或运算符
- &&在C语言中是逻辑与运算符,||在C语言中是逻辑或运算符
- 与运算符相关的内容可以查看这篇内容:C语言进制转换、操作符详解
1.3 词法分析中的贪心法
贪心法
C语言的某些符号,例如*、/、和=,只有一个字符,称为单字符符号,而C语言中的其它符号,例如/*、==、和标识符,包括了多个字符,称为多字符符号,当C编译器读入一个/字符后又跟了一个字符*,那么编译器就必须做出判断,是将其作为两个分别的符号对待,还是合起来作为一个符号对待?
C语言对这个问题的解决方案是:每一个符号应该包含尽可能多的字符,即从左到右逐字符的读入,如果该字符可能组成一个符号,那么再读入的下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分,如果可能,继续读取下一个字符,重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号
这样的处理策略被称为"贪心法"或者“大嘴法”
例如:
1、a---b 与 a-- - b含义相同,而与a - -- b不相同
2、我们想要用x除以p指针所指向的值然后将所得的商赋值给y,但是/*被编译器理解为一段注释的开始,编译器会不断的读入字符,直到*/出现为止,也就是说该语句直接将x的值赋给y,根本不会顾及后面的p:
//错误写法
y = x /* p /* p指向除数*/
//正确写法
y = x / *p /* p指向除数*/
或
y = x / (*p) /* p指向除数*/
注意事项:除了字符串与字符常量外,符号的中间不能嵌有空白(空格符、制表符和换行符),例如:==是单个符号,而= =则是两个符号
1.4 八进制数
如果一个整型常量的第一个字符为0,那么该常量将被视为八进制。因此,10与010的含义截然不同。注意!ANSC I标准禁止把8和9作为八进制数字处理,因为许多C编译器会这样做,此外还需要注意的是有时候为了上下文的格式对齐,我们可能无意中将十进制数写成了八进制数:
struct
{
int part_number;
char *description;
}parttab[] = {
046, "left" ,
047, "right" ,
125, "mid" ,
};
//parttab是一个结构体变量
1.5 字符与字符串
C语言中的单引号与多引号含义完全不同,在某些情况下如果把两者弄混,编译器并不会检测报错,从而在运行时产生难以预料的结果。
用单引号引起的一个字符实际上代表一个整数,整数值对应于该字符在编译器采用的字符集中的序列值。因此,对于该字符在编译器采用的字符集中的序列值。因此,对于采用ASCII字符集的编译器而言,‘a’的含义与0141(八进制)或97(十进制)相同。
用双引号引起的字符串,代表的却是一个指向无名数组起始字符的指针,该数组被双引号之间的字符以及一个额外的二进制值为0的字符'\0'初始化。
//语句一:
printf("hello world\n");
//语句二:
char hello[] = {'h','e','l','l','l',' ',
'w','o','r','l','d','\n',0};
printf(hello);
//两个语句产生的效果相同
注意事项:字符串常量(如 "yes"
):这是一个字符串,它实际上是一个以空字符 \0
结尾的字符数组。在内存中,"yes"
会被存储为 {'y', 'e', 's', '\0'}
,占据4个字节,并返回该字符串第一个字符的内存地址。而在一些C编译器中,允许多字符字符常量(如 'yes'
),这实际上违反了标准的字符常量的定义。根据ANSI C标准,字符常量应该只能包含一个字符,但一些编译器出于实现的灵活性,允许在单引号内包含多个字符。此时编译器会将这些字符组合成一个整数值(如何组合取决于编译器的实现方式)通常的做法是将这些字符的ASCII值按照一定的顺序组合在一起:
'y'
的ASCII值是121
'e'
的ASCII值是101
's'
的ASCII值是115
'yes' = (121 << 16) | (101 << 8) | (115)
解释:y
的ASCII值 121
被放入高位字节,e
的ASCII值 101
被放入中间字节,s
的ASCII值 115
放入最低字节。该整数的具体数值取决于编译器对这些字符值如何处理
~over~