问题描述
我知道:
int b = 1,c = 2,d = 3,e = 4;
printf("%d %d %d",++b,b,b++);
导致未定义的行为。由于
在两个序列点之间多次修改任何对象是 UB。 Undefined behavior and sequence points
但我不知道:
int b = 1,e = 4;
printf("%d",b++ + ++c - --d - e--);
也是UB吗?
我认为递增/递减运算符将首先评估,因为它们之间的优先级从右到左,因为 associativity 。然后算术运算符将从左到右求值。
就是这样
(b) + (c + 1) - (d - 1) - (e)
即 1 + (2 + 1) - (3 - 1) - (4)
= (2 - 4)
= -2
对吗?
解决方法
但我不知道:...也是UB吗?
不是,但您对原因的推理是模糊的。
我认为增量/减量运算符将首先评估,因为它们之间的优先级从右到左,因为 associativity 。然后算术运算符将从左到右求值。
优先级决定了结果的计算方式。它没有说明副作用的顺序。
没有等效的优先级告诉您在语句期间何时可以观察到副作用(b
的存储值已增加,e
的存储值已减少)是可观察的 。您只知道变量在 next 语句之前(即通过 ;
)采用了新值。
所以,这是明确定义的原因是它不依赖于那些副作用。
为了避免陷入困境,我故意用手挥舞着语言,但我可能应该澄清一下:
- “在语句中”的意思是“在下一个序列点之前”
- “在 next 语句之前 (...
;
)”真正的意思是“在下一个序列点”
- 在对所有函数参数和函数指示符求值之后,实际函数调用之前,有一个序列点。
所以真的副作用是在调用 printf
之前提交的,所以比语句末尾的 ;
早。
表达之间存在巨大差异
b++ + ++c - --d - e--
(这很好),以及
x++ + ++x - --x - x--
(这是大量未定义的)。
不是使用 ++
或 --
使表达式未定义。它甚至不会在同一个表达式中使用 ++
或 --
两次。不,问题是当您使用 ++
或 --
修改表达式中的变量时,并且您还尝试在相同的其他地方使用相同变量的值表达式,并且没有中间序列点。
考虑更简单的表达
++z + z;
现在,显然子表达式 ++z
将增加 z
。所以问题是,+ z
部分是使用 z 的旧值还是新值?答案是没有答案,这就是为什么这个表达式是未定义的。
请记住,像 ++z
do not 这样的表达式只是表示“取 z
的值并加 1”。它们的意思是“取 z
的值并加 1,然后将结果存回 z
”。这些表达式具有副作用。而副作用是不确定性问题的根源。