C陷阱与缺陷学习笔记

来源:互联网 发布:linux下的awk 编辑:程序博客网 时间:2024/05/18 02:10

第一章:词法"陷阱"
1. 编译器将程序分解成符号的方法是,从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号.
2. 如果一个整型常数的第一个字符是数字0,那么该常量将被视作八进制数.
如0195相当于十进制数141

第二章 语法"陷阱"
1. (*(void(*)())0)();的含义
void(*)()是一个函数指针,该函数返回void型数据
(void(*)())0就是将常数0转换为指向返回值为void的函数的指针
(*(void(*)())0)();就是一个表达式,调用0地址的函数

该表达式相当:
typedef void (*funcptr)();
(*(funcptr)0)();

2. 所有的赋值运算符的优先级是一样的,而且它们的结合方式是从右到左.因此
home_score = visitor_score = 0;
与下面两条语句表达意思相同:
visitor_score = 0;
home_score = visitor_score;

第三章 语义"陷阱"
1. 指针和数组
(1) C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来.(C99标准允许数组(VLA),GCC编译器中实现了变长数组,但细节与C99标准不完全一致)
(2) 对于一个数组,我们只能够做两件事:确定该数组的大小,以及获得指向该数组下标为0的元素的指针.
(3) int a[3];
sizeof(a)的结果是整个数组a的大小,而不是指向数据a的元素的指针的大小.
(4) C语言中只有四个运算符(&&, ||, ?:和,)存在规定的求值顺序.运算符&&和运算符||首先对左侧操作数求值,只在需要时才对右侧操作数求值.运算符?:有3个操作数:在a?b:c中,操作数a首先被求值,根据a的值再求操作数b或c的值.而逗号运算符,首先对左侧操作数求值,然后该值被"丢弃",再对右侧操作数求值.其他所有运算符对其操作数求值的顺序都是未定义的.特别的,赋值运算符并不保证任何求值顺序.

第六章 预处理器
1.不能忽视宏定义中的空格
#define f (x) ((x)-1)
f代表(x) ((x)-1),而不是f(x)代表((x)-1),后者应写为
#define f(x) ((x)-1)
这一规则不适用于宏调用,只对宏定义适用.因此上面完成宏定义后,f(3)与f (3)求值后都等于2.

2.assert(e)的正确定义
#define assert(e) /
             ((void)((e) || _assert_error(__FILE__,__LINE__)))
这个定义实际上利用了||运算符对两侧的操作数依次顺序求值的性质.

第七章 可移植性缺陷
(1)向右移位时,空出的位是由0填充,还是由符号位的副本填充?
如果被移位的对象是无符号数,那么空出的位将被0填充.如果被移位的是有符号数,那么C语言实现既可以用0填充空出的位,也可以用符号位的副本填充空出的位.
(2)移位计数(即移位操作的位数)允许的取值范围是什么?
如果被移位的对象长度是n位,那么移位计数必须大于或等于0,而严格小于n.
(3)大多数编译器要求余数与被除数的正负号相同.

第八章 建议与答案
(1) a+++++b的含义是什么
根据"大嘴法"规则,上式应该被分解为:
a ++ ++ + b
这个式子从语法上说是不正确的,它等价于:
((a++)++) + b
但是,a++的结果不能作为左值,因此编译器不会接受a++作为后面的++运算符的操作数.

(2)C语言允许初始化列表中出现多余的逗号,例如:
int days[] = { 31, 28, 31, 30, 31, 30,
                      31, 31, 30, 31, 30, 31,};
为什么这种特性是有用的?
我们可以把上例的缩排格式稍作改动如下:
int days[] = { 
            31, 28, 31, 30, 31, 30,
            31, 31, 30, 31, 30, 31,
};
现在我们可以很容易看出,初始化列表的每一行都是以逗号结尾的.正因为每一行在语法上的这种相似性,自动化的程序设计工具(例如,代码编辑器)才能更方便的处理很大的初始化列表.

(3)请使用宏来实现max的一个版本,其中max的参数都是整数,要求在宏max的定义中这些整数参数只被求值一次。
static int max_temp1, max_temp2;
#define max(p,q) (max_temp1=(p),max_temp2=(q),/
                             max_temp1>max_temp2 ? max_temp1 : max_temp2)
只要对max宏不是嵌套调用,上面的定义就都能正常工作.