3

誰もが知っているように、これはゼロをループします:

while (x-- > 0) { /* also known as x --> 0 */
  printf("x = %d\n", x);
}

ただしx = x--、未定義の動作が発生します。


どちらの例にも、の「return」値が必要ですがx--、これは私が推測するところにはありません。どうしてそれx-- > 0が定義されているのに定義されていx = x--ないのでしょうか?

4

5 に答える 5

19

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.

于 2011-02-07T17:28:41.373 に答える
7

「xの「戻り値」が必要ですが、そこにはありません」という考えをどこで得たのかわかりません。まず、あなたが何を意味するのかが正確には明確ではありません。第二に、あなたが何を意味するかに関係なく、これは の未定義の動作の原因とは何の関係もないようですx = x--

x = x--x介在するシーケンス ポイントなしで 2 回変更しようとするため、未定義の動作が発生します。ここでは、「戻り値」の「必要性」は関係ありません。

の根本的な問題x = x--は、未定義の瞬間に未定義の順序で発生する 2 つの副作用があることです。1 つの副作用は、代入演算子によって導入されます。別の副作用は、後置--演算子によって導入されます。どちらの副作用も同じ変数を変更しようとするものでxあり、一般的に互いに矛盾します。これが、そのような場合の動作が法定未定義と宣言される理由です。

たとえば、元の値がxだった5場合、式は同時に(デクリメントの副作用) と(代入の副作用) のx両方になる必要があります。言うまでもなく、同時になるということは不可能です。45x45

そのような単純な矛盾 ( 4vsのような5) は、UB が発生するために必要ではありませんが。シーケンス ポイントを介さずに同じ変数にヒットする 2 つの副作用があるたびに、これらの副作用が変数に入れようとしている値が一致していても、動作は未定義です。

于 2011-02-07T17:33:29.157 に答える
3

これを理解するには、シーケンスポイントの基本的な理解が必要です。このリンクを参照してください:http://en.wikipedia.org/wiki/Sequence_point

=演算子にはシーケンスポイントがないため、の値がに再度割り当てられる前に変更される保証はありませxx

whileループで条件をチェックしているときはx-- > 0x--が評価され、その値が関係演算子の評価に使用されるため、xは1回だけ変更されるため、未定義の動作が発生する可能性はありません。

于 2011-08-07T07:11:37.187 に答える
2

他の回答に何かを追加するには、シーケンスポイントに関するこのウィキペディアのページを読んでみてください。

于 2011-02-07T17:43:24.947 に答える
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 回代入することは避けてください (これには、前/後 ++/-- による変更が含まれます)。

于 2015-07-01T12:27:13.357 に答える