跳转到内容

4. 运算符总结

到此为止,除了和指针相关的运算符还没讲之外,其它运算符都讲过了,是时候做一个总结了。

运算符 + - * / % > < >= <= == != & | ^ 以及各种复合赋值运算符要求两边的操作数类型一致,条件运算符?:要求后两个操作数类型一致,这些运算符在计算之前都需要做 Usual Arithmetic Conversion。

下面按优先级从高到低的顺序总结一下 C 语言的运算符,每一条所列的各运算符具有相同的优先级,对于同一优先级的多个运算符按什么顺序计算也有说明,双目运算符就简单地用“左结合”或“右结合”来说明了。和指针有关的运算符 * & -> 也在这里列出来了,到 第 23 章 指针 再详细解释。

  1. 标识符、常量、字符串和用 () 括号套起来的表达式是组成表达式的最基本单元,在运算中做操作数,优先级最高。

  2. 后缀运算符,包括数组取下标 []、函数调用 ()、结构体取成员 .、指向结构体的指针取成员 ->、后缀自增 ++、后缀自减 --。如果一个操作数后面有多个后缀,按照离操作数从近到远的顺序(也就是从左到右)依次计算,比如a.name++,先算a.name,再++,这里的.name应该看成a的一个后缀,而不是把.看成双目运算符。

  3. 单目运算符,包括前缀自增 ++、前缀自减 --sizeof、类型转换 ()、取地址运算 &、指针间接寻址 *、正号 +、负号 -、按位取反 ~、逻辑非 !。如果一个操作数前面有多个前缀,按照离操作数从近到远的顺序(也就是从右到左)依次计算,比如!~a,先算~a,再求!。

  4. *、除 /、模 % 运算符。这三个运算符是左结合的。

  5. +、减 - 运算符。左结合。

  6. 移位运算符 <<>>。左结合。

  7. 关系运算符 < > <= >=。左结合。

  8. 相等性运算符 ==!=。左结合。

  9. 按位与 &。左结合。

  10. 按位异或 ^。左结合。

  11. 按位或 |。左结合。

  12. 逻辑与 &&。左结合。

  13. 逻辑或 ||。左结合。

  14. 条件运算符:?。在第 2 节“if/else 语句”讲过 Dangling-else 问题,条件运算符也有类似的问题。例如a ? b : c ? d : e是看成(a ? b : c) ? d : e还是a ? b : (c ? d : e)呢?C 语言规定是后者。

  15. 赋值 = 和各种复合赋值(*= /= %= += -= <<= >>= &= ^= |=)。在双目运算符中只有赋值和复合赋值是右结合的。

  16. 逗号运算符。左结合。

K&R 第 2 章也有这样一个列表,但是对于结合性解释得不够清楚。左结合和右结合这两个概念只对双目运算符有意义,对于前缀。后缀和三目运算符我单独做了说明。C 语言表达式的详细语法规则可以参考 C99 的 Annex A.2,其实语法规则并不是用优先级和结合性这两个概念来表述的,有一些细节用优先级和结合性是表达不了的,只有看 C99 才能了解完整的语法规则。

习题

  1. 以下代码得到的sum是 0xffff,对吗?

    c
    int i = 0;
    unsigned int sum = 0;
    for (; i < 16; i++)
        sum = sum + 1U<<i;