运算符的优先级&同优先级内的结合性&序列点

本文深入探讨了C语言中的运算符优先级、结合性及序列点的概念。通过多个实例解释了如何正确理解并应用这些原则,帮助读者避免常见的编程陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

运算符的优先级&同优先级内的结合性&序列点

本文以C语言为基础来进行探讨。

参考资料:

运算符的结合性:
https://en.wikipedia.org/wiki/Operator_associativity
c的优先级与结合性:
https://msdn.microsoft.com/en-us/library/2bxt6kc4.aspx
https://msdn.microsoft.com/en-us/library/126fe14k.aspx
http://en.cppreference.com/w/c/language/operator_precedence
http://en.cppreference.com/w/cpp/language/operator_precedence
边效应:
https://msdn.microsoft.com/en-us/library/8a425116.aspx
https://gcc.gnu.org/onlinedocs/gccint/Side-Effects.html
https://gcc.gnu.org/onlinedocs/cpp/Duplication-of-Side-Effects.html
序列点:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf 的附录C
https://msdn.microsoft.com/en-us/library/azk8zbxd.aspx
http://en.cppreference.com/w/cpp/language/eval_order
https://en.wikipedia.org/wiki/Sequence_point
最大匹配:
c语言n1256.pdf 的6.4 Lexical elements第4段落
https://en.wikipedia.org/wiki/Maximal_munch

优先级Precedence

基础知识略。参考Microsoft的C语言文档。

例子:

  • *p++ : 后缀++的优先级高于*,所以解析成 *(p++) 而不是 (*p)++
  • a & b || c : 位与运算符&的优先级高于||,所以解析成 (a & b) || c
  • a = b || c : 解析成 a = (b || c)
  • 1 || 0 && 0 解析成 1 || (0 && 0) 结果是1
  • q && r || s-- : 解析成 (q && r) || (s––)
  • a.b++ : 解析成 (a.b)++

结合性Associativity

结合性就是指,当同等优先级的操作符一起出现时,怎么将操作数和操作符分组(或说绑定)(以确定运算顺序)。

In programming languages, the associativity (or fixity) of an operator is a property that determines how operators of the same precedence are grouped in the absence of parentheses.

If an operand is both preceded and followed by operators (for example, “^ 4 ^“), and those operators have equal precedence, then the operand may be used as input to two different operations (i.e. the two operations indicated by the two operators). The choice of which operations to apply the operand to, is determined by the “associativity” of the operators.

注意:结合性只有在出现同等优先级操作符的时候才需要考虑(Associativity is only needed when the operators in an expression have the same precedence)。

一般来讲,操作符的结合性有4种:

  • associative (meaning the operations can be grouped arbitrarily)
  • left-associative (meaning the operations are grouped from the left)
  • right-associative (meaning the operations are grouped from the right)
  • non-associative (meaning operations can not be chained, often because the output type is incompatible with the input types)

比如,抽象表达式 a ~ b ~ c 中,~代表某操作符,其结合性如果:

  • left associativity,即从左到右:解析为(a ~ b) ~ c
  • right associativity,即从右到左:解析为a ~ (b ~ c)
  • 其他结合性定义:则其他特殊意义。

代入一个具体的例子,例如 7 − 4 + 2 中,假设+-操作符具有同等优先级,如果:

  • +-都是左结合性: (7 − 4) + 2 = 5
  • +-都是右结合性: 7 − (4 + 2) = 1

下面是一个更详细的例子,来说明结合性
表达式 5^4^3^2 ,这里 ^ 代表幂运算。语法分析器(parser)从左向右扫描读入该表达式。

  • 这里如果幂运算符^右结合性,即从右向左结合顺序,则:

    1. 读入5
    2. 读入^,现在节点是5^
    3. 读入4,现在节点是5^4
    4. 读入^,现在节点是5^(4^
    5. 读入3,现在节点是5^(4^3
    6. 读入^,现在节点是5^(4^(3^
    7. 读入2,现在节点是5^(4^(3^2
    8. 没有token可读,结束,现在节点是5^(4^(3^2))

    接下来,进行求值(depth-first),从树最顶端的^开始走:

    1. 求值程序(evaluator)沿着树,从第一个、经过第二个、到达第三个^表达式
    2. 计算3^2=9,这个结果替换到第二个^的表达式中
    3. 继续在parse tree的向上一层,计算4^9=262144,同样地这个结果替换到第一个^表达式中作为其操作数
    4. 继续向上一层,计算5^262144=...得到结果,最后这棵树就可以销毁了并返回总结果
    5. 结束
  • 这里如果幂运算符^左结合性,则计算式被解析成: ((5^4)^3)^2 ,当然运算结果和上面就不一样了。

序列点Sequence point

边效应Side Effects

最大匹配规则Maximal munch

词法分析器读入能构成有意义标记结构的最多的连续输入(the longest sequence of characters that could constitute a preprocessing token)。

例如:

  • x+++y : 因为从左向右能构成的最大有意义标记是++运算符,所以解析成 (x++)+y ,而不是x+(++y)
  • x+++++y : 同理,被解析成(x++)(++)(+y),所以编译报错。

这里需要注意的是“连续输入”。
例如在x+++y中,三个+字符是连续的,所以被解析成了(x++)+y;但如果是x+ ++y在第一个+符后面跟了空白,那么一般的词法分析器就会把该语句解析成x+(++y)
同理,如果写成x+++ ++y的表达式,就可以编译通过了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值