C++实践:运算符优先级“错误”

运算符是基本的语言元素,虽然接触编程语言的年岁不短了,但有时面对着一些表达式,仍不能立马确认运算顺序。我相信很多人也有我这方面的疑惑,今天就把一些“设计错误”的运算符拉出来溜溜。

& 和 |

看下面的代码片段,变量a的值是多少呢?

int a = 1 | 0 == 1 & 0;

对于表达式1 | 0 == 1 & 0,包含三个运算符,已知&优先级高于|,并且这些位操作符要么高于==,要么低于==,分两种情况讨论:

  1. 位操作符优先级高于==
    等价于(1 | 0) == (1 & 0),计算的结果为0
  2. ==优先级高于位操作符
    等价于1 | ((0 == 1) & 0)),计算的结果为1

将上面的代码运行打印会得到a的值为1。这说明==优先级高于位操作符。这或许是我最迷惑的运算符规则了,在我看来位操作符本质上是算术运算符,都是产生一个数,应该跟算术运算符的规则大体一致。故而,我认为第一种更合理。

是不是设计的错误呢,终于在《C专家编程》这本书里找到了答案,即下节。

'And' and 'AND' or 'Or' or 'OR'

来自C语言的创造者 Dennis Ritchie 的解释:

&&|| 操作符与  == 操作符的优先级关系问题是这样产生的。在 C 的早期, & 和  && 合用同一个操作符,  | 和  || 也是如此(明白吗?)。 它继承了 B 和 BCPL 中的概念“真值上下文”。就是在  if 和  while 等后面需要一个布尔值的时候, & 和  就被翻译成现在的  && 和  ||。如果它们在一般的表达式里,就被解释成位操作符,也就是现在的样子。这个机制操作起来没有问题,但理解起来很困难(在真值上下文里,存在“顶层运算符”的概念)。

& 和 | 的优先级跟现在一样。最初,在 Alan Snyder 的催促下,我在C语言中加入了 && 和 ||操作符。这就成功地把位运算的概念和布尔运算的概念分了开来。然而,我心怀不安,因为我意识到了优先级的问题。例如,在现存的大量程序中,存在诸如这样的表达式: if(a == b & c == d)

事后回想,如果我们一开始就改变优先级,让&的优先级高于==,在逻辑上可能更清晰一些。但是,从安全的角度出度,只能做到把 & 和 && 分开这个程度,无法在两者的优先级之间再插入其他的操作符(否則的话,现有的大量代码都有可能出问題)。

从上面的描述可以看出,最终设计的结果在于代码兼容性上的考量。Java 和 C# 的操作符优先级跟C/C++ 大同小异,这可以认为是另一个层次的兼容:程序员的编码习惯。

C++其他不合理的操作符

在《C专家编程》这本书里还列出了其他错误的操作符,这里一并列出:

优先级问题表达式人们可能误以为的结果实际结果
.的优先级高于*。->优先级用于消除这个问题*p.fp所指对象的字段f。 (*p).f对p取f偏移,作为指针,然后进行间接引用操作。*(p.f)
[]高于*int *ap[]ap是个指向int数组的指针。int(*ap)[]ap是个元素为int指针的数组。int *(ap[])
函数()高于*int *fp()fp是个函数指针,所指函数返回int。int (*fp)()fp是个函数,返回int。int(fp())
==和!=高于位操作符(val & mask != 0)(val & mask)!= 0val & (mask != 0)
==和!=高于赋值符c=getchar()!=EOF(c=getchar())!=EOFc=(getchar()!=EOF)
算术运算符高于移位运算符msb << 4 + lsb(msb << 4) + lsbmsb << (4 + lsb)
逗号运算符在所有运算符中优先级最低i=1,2i=(1,2)(i=1),2

这些不合理的操作符毕竟占了少数,遇到它们完全可以使用括号保证可靠性,同时不会影响代码的可读性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值