此 C 代码是否会导致未定义的行为?
Does this C code result in Undefined Behavior?
我知道:
int b = 1, c = 2, d = 3, e = 4;
printf("%d %d %d", ++b, b, b++);
导致未定义的行为。自
Modifying any object more than once between two sequence points is UB.
Undefined behavior and sequence points
但我不知道是否:
int b = 1, c = 2, d = 3, e = 4;
printf("%d", b++ + ++c - --d - e--);
也是UB吗?
我认为 increment/decrement 运算符将首先计算,因为它们之间的优先级是从右到左,因为关联性。然后算术运算符将从左到右求值。
这将是
(b) + (c + 1) - (d - 1) - (e)
that is, 1 + (2 + 1) - (3 - 1) - (4)
= (2 - 4)
= -2
对吗?
But I don't know if: ... is also UB?
不是,但是你的推理很模糊。
What I think is that increment/decrement operators will evaluate first because of the precedence, between them right to left since the associativity . Then arithmetic operators will be evaluated left to right.
优先级决定了结果的计算方式。它没有说明副作用的顺序。
当副作用(b
的存储值已递增,e
的存储值已递减)何时可观察到时,没有等效的优先级告诉您 在声明中。您所知道的是,变量在 next 语句之前(即通过 ;
)获得了新值。
所以,这是明确定义的原因是它不依赖于那些副作用。
为了避免陷入困境,我故意挥舞着语言,但我应该澄清一下:
- "during the statement" 真正的意思是"在下一个序列点"之前
- “在 next 语句之前 (...
;
)” 真正的意思是“ 在下一个序列点 ”
- There is a sequence point after the evaluation of all function arguments and of the function designator, and before the actual function call.
所以真的副作用是在调用printf
之前提交的,所以早于语句末尾的;
。
表达方式有天壤之别
b++ + ++c - --d - e--
(很好),
x++ + ++x - --x - x--
(严重未定义)。
它没有使用 ++
或 --
使表达式未定义。它甚至没有在同一个表达式中使用 ++
或 --
两次。不,问题是当您使用 ++
或 --
修改表达式中的变量时, 和 您还尝试在其他地方使用相同变量的值在同一个表达式中,并且没有中间序列点。
考虑更简单的表达式
++z + z;
现在,显然子表达式 ++z
将递增 z
。那么问题来了,+ z
部分使用的是 z 的旧值还是新值?而答案是没有答案,这就是这个表达式未定义的原因。
记住,像 ++z
这样的表达式做 而不是 只是意味着,“取 z
的值并加 1”。他们的意思是,“取 z
的值并加 1,并将结果存回 z
”。这些表达式具有 副作用 。副作用是不确定性问题的根源。
我知道:
int b = 1, c = 2, d = 3, e = 4;
printf("%d %d %d", ++b, b, b++);
导致未定义的行为。自
Modifying any object more than once between two sequence points is UB. Undefined behavior and sequence points
但我不知道是否:
int b = 1, c = 2, d = 3, e = 4;
printf("%d", b++ + ++c - --d - e--);
也是UB吗?
我认为 increment/decrement 运算符将首先计算,因为它们之间的优先级是从右到左,因为关联性。然后算术运算符将从左到右求值。
这将是
(b) + (c + 1) - (d - 1) - (e)
that is, 1 + (2 + 1) - (3 - 1) - (4)
= (2 - 4)
= -2
对吗?
But I don't know if: ... is also UB?
不是,但是你的推理很模糊。
What I think is that increment/decrement operators will evaluate first because of the precedence, between them right to left since the associativity . Then arithmetic operators will be evaluated left to right.
优先级决定了结果的计算方式。它没有说明副作用的顺序。
当副作用(b
的存储值已递增,e
的存储值已递减)何时可观察到时,没有等效的优先级告诉您 在声明中。您所知道的是,变量在 next 语句之前(即通过 ;
)获得了新值。
所以,这是明确定义的原因是它不依赖于那些副作用。
为了避免陷入困境,我故意挥舞着语言,但我应该澄清一下:
- "during the statement" 真正的意思是"在下一个序列点"之前
- “在 next 语句之前 (...
;
)” 真正的意思是“ 在下一个序列点 ”
- There is a sequence point after the evaluation of all function arguments and of the function designator, and before the actual function call.
所以真的副作用是在调用printf
之前提交的,所以早于语句末尾的;
。
表达方式有天壤之别
b++ + ++c - --d - e--
(很好),
x++ + ++x - --x - x--
(严重未定义)。
它没有使用 ++
或 --
使表达式未定义。它甚至没有在同一个表达式中使用 ++
或 --
两次。不,问题是当您使用 ++
或 --
修改表达式中的变量时, 和 您还尝试在其他地方使用相同变量的值在同一个表达式中,并且没有中间序列点。
考虑更简单的表达式
++z + z;
现在,显然子表达式 ++z
将递增 z
。那么问题来了,+ z
部分使用的是 z 的旧值还是新值?而答案是没有答案,这就是这个表达式未定义的原因。
记住,像 ++z
这样的表达式做 而不是 只是意味着,“取 z
的值并加 1”。他们的意思是,“取 z
的值并加 1,并将结果存回 z
”。这些表达式具有 副作用 。副作用是不确定性问题的根源。