C陷阱与缺陷——第2章语法陷阱

1. 理解函数声明

硬件将调用首地址为0位置的子例程

(*(void(*)())0)();

任何C变量的声明都由两部分组成:类型以及一组类似表达式的声明符,声明符从表面看与表达式有些类似,对它求值应该返回一个声明中给定类型的结果。

假定变量fp是一个函数指针,那么如何调用fp所指向的函数的调用方法如下:

(*fp)();

ANSI C标准允许程序员将上式简写为fp(),但是一定要记住这种写法只是一种简写形式。

我们一旦知道如何声明一个变量,也就自然知道如何对一个常数进行类型转换,将其转型为该变量的类型:知需要在变量声明中将变量名去掉即可。

硬件将调用首地址为0位置的子例程可读性更好的写法如下:

typedef void (*funcptr)();
(*(funcptr)0)();

signal函数接受两个参数:

  • 一个整型的信号编号
  • 一个指向用户定义的信号处理函数的指针

声明signal函数:

void (*signal(int, void(*)(int)))(int);

也可以使用typedef简化上面的函数声明:

typedef void (*HANDLER)(int);
HANDLER signal(int, HANDLER);

2. 运算符的优先级问题

优先级最高的并不是真正意义上的运算符,包括数组下标、函数调用操作符、结构成员选择操作符,括号,自左向右结合。

单目运算符优先级仅次于前述运算符,自右向左结合。

单目运算符中,算术运算符最高,移位运算符次之,关系运算符再次之,接着是逻辑运算符,赋值运算符,最后是条件运算符(实际上是三目运算符)

  • 任何一个逻辑运算符的优先级低于任何一个关系运算符
  • 移位运算符的优先级比算法运算符要低,但是比关系运算符要高

运算符==和!=的优先级要低于其他关系运算符的优先级

所有的赋值运算符优先级是一样的,而且它们的结合方式是右到左

在所有的运算符中,逗号的优先级最低

3. 注意作为语句结束标志的分号

4. switch语句

switch的case后需要加上break才会退出switch,不然会继续往下执行其他case,这个特性既是优势,也是一个弱点,但不使用break时,最好加上注释

5. 函数调用

C语言要求:在函数调用时即使函数不带参数,也应该包括函数列表。

6. 悬挂else引发的问题

else始终与同一括号内最近的未匹配的if结合

通过宏定义也可以悬挂else问题:

#define IF      {if(
#define THEN    ){
#define ELSE    }else{
#define FI      }}

使用过程如下:

IF x == 0
THEN IF y == 0
     THEN error();
     FI
ELSE z = x + y;
f(&z);
IF

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值