用圆括号分组

在前面几节中,我们已经多次看到,由于运算优先级,一些表达式可能会产生意外结果。为了明确地改变计算顺序,我们应该使用圆括号。表达式中带圆括号的部分无论其默认优先级如何,都会比周围表达式具有更高优先级。成对的圆括号可以嵌套,但建议嵌套层数最多 3 到 4 层。最好把过于复杂的表达式分成几个简单表达式。

ExprParentheses.mq5 脚本展示了在表达式中放置圆括号的演算过程。其最初目的是使用左移运算 '<<' 在 flags 变量中设置位。如果位编号不为零,则从 offset 变量获取位编号,否则位编号取 1(切记,编号从零开始)。然后将获得的值乘以 coefficient。我们不用纠结这个例子有没有实际意义。但代码中的确可能出现更复杂的结构。

int offset = 8;
int coefficient = 10flags = 0;
int result1 = coefficient * flags | 1 << offset > 0 ? offset : 1;     // 8
int result2 = coefficient * flags | 1 << (offset > 0 ? offset : 1);   // 256
int result3 = coefficient * (flags | 1 << (offset > 0 ? offset : 1)); // 2560

不带圆括号的第一个版本,甚至会让编译器产生自我怀疑。编译器给出一个我们熟悉的警告:“表达式不是布尔型”。问题是三元条件运算符是这里所有运算符中优先级最低的。基于此,'?' 之前的整个左边部分都被认为是它的条件。在条件中,按以下顺序进行计算:乘法、按位移位、“大于”比较和按位“或”运算,因此计算结果是一个整数。当然,可以将计算结果用作 truefalse,但是最好使用 显式类型强制转换将这种意图“传达”给编译器。如果不进行类型强制转换,编译器显然有理由认为该表达式有问题。第一次计算的结果是 8。这是不正确的。

让我们在三元运算符两边加上圆括号。编译器的警告就会消失。然而,表达式仍然计算错误。由于乘法的优先级高于按位“或”的优先级,因此 coefficientflags 变量先进行相乘,然后再与左移获得的位掩码结合。结果是 256。

最后,添加另一对圆括号后我们得到了正确结果:2560。