让我举一个例子:
a = ++a;
据说上述陈述有不明确的行为(我已经在SO上读过关于UB的文章)
但是根据优先级规则运算符前缀++
的优先级高于赋值运算符=
所以a
应首先递增,然后再分配给a。所以每个评估都是已知的,为什么它是UB?
答案 0 :(得分:9)
这里要理解的重要一点是,操作员可以生成值,也可以有副作用。
例如++a
生成(评估为)a + 1
,但它也有增加a
的副作用。 a = 5
也是如此(计算结果为5,同时将a
的值设置为5)。
所以你在这里有两个副作用会改变a
的值,这两个副作用都发生在序列点之间(可见的分号和前一个语句的结尾)。
由于运算符优先级,定义两个运算符的顺序是明确定义的,这一点无关紧要,因为处理副作用的顺序仍未定义。
因此UB。
答案 1 :(得分:3)
优先级是解析表达式的语法规则的结果。 ++
优先级高于=
的事实仅表示++
绑定到其操作数“比=
更严格”。实际上,在您的示例中,由于运算符的显示顺序,只有一种方法可以解析表达式。在诸如a = b++
之类的示例中,语法规则或优先级保证这意味着与a = (b++)
相同而不是(a = b)++
。
优先级与表达式的评估顺序或表达式的副作用的顺序几乎没有关系。 (显然,如果操作符根据语法规则操作另一个表达式 - 或优先级 - 那么必须在应用运算符之前计算该表达式的值,但是大多数独立的子表达式可以按任何顺序和侧面计算 - 效果也按任何顺序处理。)
答案 2 :(得分:1)
为什么是UB?
因为它试图在一个序列点之前两次更改变量a
:
答案 3 :(得分:1)
序列点评估#6:在初始化器结束时;例如,在声明int a = 5;中评估5之后。来自维基百科。
您正尝试更改相同的变量a,两次。 ++ a更改它,赋值(=)更改它。但是,在分配结束之前,序列点尚未完成。因此,虽然它对我们来说是完全有意义的 - 标准不能保证标准能够提供正确的行为,因为标准表示不会在序列点中多次更改某些内容(简单地说)。
答案 4 :(得分:0)
它有点微妙,但可以解释为以下之一(并且编译器不知道哪个:
a=(a+1);a++;
a++;a=a;
这是因为语法中含糊不清。