誰もが知っているように、これはゼロをループします:
while (x-- > 0) { /* also known as x --> 0 */
printf("x = %d\n", x);
}
ただしx = x--
、未定義の動作が発生します。
どちらの例にも、の「return」値が必要ですがx--
、これは私が推測するところにはありません。どうしてそれx-- > 0
が定義されているのに定義されていx = x--
ないのでしょうか?
Because in x = x--
you're modifying the value of x
twice without an intervening sequence point. So the order of operations is not defined. In x-- > 0
the value of x
is modified once, and it is clearly defined that result of evaluating x--
will be the value of x
before the decrement.
「xの「戻り値」が必要ですが、そこにはありません」という考えをどこで得たのかわかりません。まず、あなたが何を意味するのかが正確には明確ではありません。第二に、あなたが何を意味するかに関係なく、これは の未定義の動作の原因とは何の関係もないようですx = x--
。
x = x--
x
介在するシーケンス ポイントなしで 2 回変更しようとするため、未定義の動作が発生します。ここでは、「戻り値」の「必要性」は関係ありません。
の根本的な問題x = x--
は、未定義の瞬間に未定義の順序で発生する 2 つの副作用があることです。1 つの副作用は、代入演算子によって導入されます。別の副作用は、後置--
演算子によって導入されます。どちらの副作用も同じ変数を変更しようとするものでx
あり、一般的に互いに矛盾します。これが、そのような場合の動作が法定未定義と宣言される理由です。
たとえば、元の値がx
だった5
場合、式は同時に(デクリメントの副作用) と(代入の副作用) のx
両方になる必要があります。言うまでもなく、同時になるということは不可能です。4
5
x
4
5
そのような単純な矛盾 ( 4
vsのような5
) は、UB が発生するために必要ではありませんが。シーケンス ポイントを介さずに同じ変数にヒットする 2 つの副作用があるたびに、これらの副作用が変数に入れようとしている値が一致していても、動作は未定義です。
これを理解するには、シーケンスポイントの基本的な理解が必要です。このリンクを参照してください:http://en.wikipedia.org/wiki/Sequence_point
=
演算子にはシーケンスポイントがないため、の値がに再度割り当てられる前に変更される保証はありませx
んx
。
whileループで条件をチェックしているときはx-- > 0
、x--
が評価され、その値が関係演算子の評価に使用されるため、x
は1回だけ変更されるため、未定義の動作が発生する可能性はありません。
他の回答に何かを追加するには、シーケンスポイントに関するこのウィキペディアのページを読んでみてください。
https://stackoverflow.com/a/21671069/258418を読むことをお勧めします。シーケンスポイント=
ではないものを一緒にチャックし、コンパイラーが自由に操作をインターリーブできる場合、リンクされた回答からシーケンスポイントで区切られていない限り、次の2つのシーケンスが有効であることがわかります。
load i to reg
increment i
assign reg to i
=> i has previous value of i
load i to reg
assign reg to i
increment i
=> i has value of previous value of i + 1
一般に、1 つの式で同じ変数に 2 回代入することは避けてください (これには、前/後 ++/-- による変更が含まれます)。