C/C++编译器如何根据运算符优先级和结合性分离标记?

3
考虑以下代码:
int a = 3;
int b = 0;
b = a > 0 ? ++b, ++a : --a, b = 0;

执行后,b 的值变成了0a 的值变成了4。这意味着条件表达式a > 0的结果被判断为true,并且执行了表达式a++,同时在逗号之后也执行了表达式b = 0。换句话说,表达式b = 0不是三元运算符的操作数,而++b是。否则,如果条件表达式的结果不是falseb = 0就不会被执行。 我的问题是:“编译器根据什么规则将b = 0从三元运算符的操作数中剔除?” 第三个语句中的运算符包括:++--,它们具有最高的优先级;>,其次;? :=,它们的优先级排在第三位;最后是优先级最低的,。我知道具有更高优先级的运算符应该先确定它们的操作数,因此首先处理++-->。然后,该语句等价于:
b = (a > 0) ? (++b), (++a) : (--a), b = 0;

现在轮到处理=?:=?:的结合方向是从右到左,所以我认为编译器将从右端解析语句。第一个遇到的运算符是=,因此b = 0被分组在一起。接下来遇到的操作符是,。由于它的优先级低于当前正在分析的操作符,因此我假设编译器会跳过它。然后编译器遇到了:,这是三元运算符的一部分,所以它继续解析。(实际上在解析整个三元运算符之前,我不知道编译器怎么能知道:?:的一部分)问题出现在这里。编译器遇到的下一个运算符是,,但编译器还没有确定?:的操作数。逗号的优先级低于?:。理论上应该跳过它;令人惊讶的是,在实际测试中,此时(++b)(++a)已被逗号运算符连接,并且都被视为?:的操作数。这使我感到困惑。为什么最后一个,被忽略了,而不包含在?:的操作数中,而在语句中的前一个,被保留在三元运算符的操作数中呢?
可以用这个例子来阐明优先级和结合性的概念吗?当我第一次看到这段代码时,我真的感到很困惑。我曾经认为表达式b = 0也是三元运算符的一部分;因此,只有在a>0false时,b = 0才会执行。
提前感谢您的帮助。

1
int b; 然后 ++b 看起来像是未定义行为。 - gsg
是的,我已经更正了b的声明。原本b是一个具有全局作用域的变量,因此它将被初始化为0。谢谢你提醒我。 - Michael Lu
2个回答

6

优先级和结合性是不同的概念,但在C和C++标准中并没有指定它们。相反,它们给出了语法规则来推导表达式的结构。

相关规则如下:

conditional-expression:
    logical-or-expression
    logical-or-expression ? expression : assignment-expression

expression:
    assignment-expression
    expression , assignment-expression

primary-expression:
    ( expression )

postfix-expression:
    primary-expression
    ...

理念是每种类型的表达式都可以生成一个复合表达式或优先级较低的另一种表达式。只能使用括号才能到达根 expression

考虑到这一点,注意使用 ?conditional-expression 实际上在每个子表达式中具有不同类型的表达式。 中间的表达式是 expression,因此它将接受任何类型的表达式,甚至包含 ,=(由于结尾的 :,这里没有歧义)。

但请注意,最后一个是 assignment-expression,即除了带有,的任何类型的表达式之外的表达式。如果要使用它,您必须用 () 将其括起来,创建一个 primary-expression

额外解释:第一个表达式是 logical-or-expression,如果您仔细查看语法,您会发现它排除了赋值操作符、条件操作符和逗号操作符。

所以你的表达式:

b = a > 0 ? ++b, ++a : --a, b = 0

实际上是一个表达式逗号赋值表达式,其中第一个表达式b = a > 0 ? ++b, ++a : --a,而第二个赋值表达式b = 0

等等...


0

您的表达式被评估为(b = ((a > 0) ? (++b, ++a) : (--a))), (b = 0);

正如您所说,?:比逗号运算符具有更高的优先级,因此b=0不属于三元条件运算符。左侧和右侧的差异在于,在左侧,编译器尝试将完整的字符串++b, ++a作为表达式进行评估(知道之间的部分必须是表达式),而在右侧,编译器尝试尽可能解析表达式。操作符的优先级表示编译器必须停在,处。在左侧,编译器不会停在,上,因为这是表达式的合法部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接