细说C语言的优先级

0. 为什么要掌握优先级

    想想这两个问题:

            a. 读别人的代码,遇到优先级问题看不懂,怎么办?

            b. 一堆的括号,美观吗?

    本想贴一张画来装饰墙壁,却用了一堆纸来固定! 

    有人说代码写多了,自然就会了。这个是很宽泛的说法。看你写的代码的水准,有些东西可能你一直都接触不到,何谈熟练。有些东西一定要梳理,总结。


1. 优先级

1.1 优先级图表

                                  

        优先级最高者不是真正意义上的运算符,包括:数组下标,函数调用,结构体成员选择符。

        单目运算符的优先级次之。(! ~ ++ -- - (type) * & sizeof)

        然后是双目运算符。双目运算符里, 算数运算符(* / % + -)优先级最高, 移位(<< >>)次之, 关系运算符(< <= > >= != ==)再次之, 接着是位运算符(& ^ | ),逻辑运算符(&& ||) 条件运算符(?: 三目),赋值运算符(= ...)。

        任何一个逻辑运算符的优先级低于任何一个关系运算符。

        移位运算符的优先级比算数运算符要低,但是比关系运算符要高。


1.2 运算符实例

        a.代码:

while (c = getc(in) != EOF)
    putc(c, out)

        循环的意思是复制一个文件到另一个文件。但是由于!=的优先级比赋值运算符的优先级高,所以c被赋予了getc()的返回值与EOF比较后的布尔值,结果向out中写入了一堆1.


        b. 解释下面几个声明

char *p[];
char (*p)[];
int *fp();
int (*fp)();
char *p[]
                常常被错误的理解为指向字符数组的指针。         

                正确的是p一个数组,里面元素是指向字符的指针类型。


        char (*p)[]

                p是指向指向字符数组的指针。


        int *fp()

                常常错误理解为函数指针,该函数返回int类型。

                正确的是fp是一个函数,他返回一个执行int的指针。


        int (*fp)()

                fp是函数指针,该函数返回int类型。

        

        c. 解释下面的表达式

*p.f;
val & mask != 0;
max = val1 > val2 ? val1 : val2;

            对p去f偏移,作为指针,然后进行解引用。相当与*(p.f),因为.的优先级高于*。(比较(*p).f?)         *p.f

        

        val & mask != 0

                相当与val & (mask != 0).


        max = val1 > val2 ? val1 : val2

                相当与 max = (val1 > val2 ? val1 :val2).

        

        d. 一个复杂的声明

char *(* c[10])(int **p);
           c是一个数组,里面放10指针,后面紧跟这一个括号,所以这些指针是函数指针。        

1. 有两个小括号,小括号的结合行是自左向右,所以我们先关注第一个小括号,简化声明(*c[10])();


        2. 关注第二个括号,(int **p)

           显然p是函数的参数,它是个指向指针的指针。


        3. 这看最前面的*

           char *说明该函数的返回值是一个指向字符的指针。


        4. 这个声明的意思就是:c是一个数组,里面有10个函数指针,指向的函数返回指针,指向字符,函数的参数

           是指向int类型指针的指针。


1.3 优先级顺口溜

        醋坛酸味灌

        味落跳福豆


        共44个运算符


        醋-初等,4个: ( ) [ ] -> 指向结构体成员 . 结构体成员

        坛-单目,9个: ! ~ ++ -- -负号 (类型) *指针 &取地址 sizeof长度

        酸-算术,5个: * / % + -减

        味-位移,2个: << >>

        灌-关系,6个: < <= > >= == 等于 != 不等于

        味-位逻,3个: & 按位与 ^ 按位异或 | 按位或

        落-逻辑,2个: && 逻辑与 || 逻辑或

        跳-条件,1个,三目: ? :

        福-赋值,11个: = += -= *= /= %= >>= <<= &= ^= |=

        豆-逗号,1个: , 


2. 结合性

        在标准C语言的文档里,对操作符的结合性并没有作出非常清楚的解释。一个满分的回答是:它是仲裁者,在几个操作符具有相同的优先级时决定先执行哪一个。

        看例子:

int a, b = 1, c = 2;
a = b = c;
        同级的操作符,结合性相同。如果在计算表达式的值时候需要考虑结合性,那么最好把这个表达式一分为二。         这个表达式只有赋值符,这样优先级就无法帮助我们呢决定哪个操作先执行。如果a = b先执行,然后 b = c执行。那么a最终取1。如果b = c先执行, a = b后执行,那么a最终取2。到底哪一个先执行?看结合性,复制的结合性是右至左,所以b = c,然后a = b。


3. 参考资料

        《c Traps and Pitfalls》 Andrew Koenig著, ISBN 978-7-115-17179-5

        《c 专家编程》 Peter Van Der Linden 著, ISBN 978-7-115-17180-1

        顺口溜 http://blog.sina.com.cn/s/blog_4e64e2290100be0z.html


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值