读《c陷阱与缺陷》后总结记录

1.词法分析中的贪心法

问:如何理解a- - -b;

C语言的规则:每一个符号应该包含尽可能多的字符即从左到右,尽力将多个字符组成一个符号。

答:先读入a,再读入-,又发现一个-,可以组成后置- -,故读入- -。再读入-b。即(a- -)-b;

同理,对于y=x/p;编译器会读成注释符,而非x除p。正确写法应为y=x/(*p);

附题:a+++++b怎么读入?(注意a++返回的常量不能作为++的对象)

2.运算符的优先级

C语言运算符优先级表
注:assignment为赋值运算符

3.assert宏的实现

第一次尝试#define assert(e) if(!e) assert_error(__FILE__,__LINE__)
失败场景:

if(x && y)
	assert(y);
else
	assert(x);
//展开后
if(x && y)
	if(!x) 
		assert_error("test.c",6);
else
	if(!y) 
		assert_error("test.c",8);

显然后面的else与if组成else if。mission failed!
第二次尝试:用大括号括起来
#define assert(e) {if(!e) assert_error(__FILE__,__LINE__);}
失败场景:

//展开后
if(x && y)
{
	if(!x) 
		assert_error("test.c",6);
}
;//此处报错,因为这个空语句的存在,else无法匹配
else
{
	if(!y) 
		assert_error("test.c",8);
}
;

可以在assert语句后不加分号,但我们通常选择使用assert()后带分号。
正确定义#define assert(e) ((void)((e)||_assert_error(__FILE__,__LINE__)))
巧妙运用了||的特性:如果e为假,执行后面报错;如果e为真,则跳过后面。至于void强转,作用不太清楚 😢。

4.宏不是typedef

#define T1 struct A*
typedef struct A* T2;
T1 a,b;
T2 c,d;
struct A* a,b;//宏替换导致b不是结构体指针
struct A* a,*b;//typedef的则均为指针

5.一些有趣的关于函数指针表达式

(*(void(*)())0)();表示先对0进行类型强转,转为一个函数指针,这个函数指针指向的函数返回值为void且无参数,再使用0这个函数指针。
void (*signal(int,void(*)(int)))(int);声明一个函数signal,参数第一个是int,第二个是一个指向空返回值且参数为int的函数的函数指针,返回一个指向空返回值且参数为int的函数的函数指针。

暂且总结到这里了,以上都是看完书后觉得有用且有趣の知识,就记录下来了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值