1.词法分析中的贪心法
问:如何理解a- - -b;
C语言的规则:每一个符号应该包含尽可能多的字符。即从左到右,尽力将多个字符组成一个符号。
答:先读入a,再读入-,又发现一个-,可以组成后置- -,故读入- -。再读入-b。即(a- -)-b;
同理,对于y=x/p;编译器会读成注释符,而非x除p。正确写法应为y=x/(*p);
附题:a+++++b怎么读入?(注意a++返回的常量不能作为++的对象)
2.运算符的优先级
注: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的函数的函数指针。
暂且总结到这里了,以上都是看完书后觉得有用且有趣の知识,就记录下来了。