2つの整数の変数を交換するのではなく、一時的なストレージを使用しての容疑者「賢い」(実際には非効率的な)方法は、多くの場合、この行を含み、シーケンスポイントではありませんか? これは実際には未定義の動作であることを意味しますか?式a^= b^= a^= bにシーケンスポイントがありますか、それとも未定義ですか? <code>^=</code>よう </p> <pre><code>int a = 10; int b = 42; a ^= b ^= a ^= b; /*Here*/ printf("a=%d, b=%dn", a, b); </code></pre> <p>しかし、私は思ったんだけど、複合代入演算子は次のとおりです。
答えて
a ^= b ^= a ^= b; /*Here*/
これは未定義の動作です。
2つのシーケンスポイント間でオブジェクト(a
)を複数回修正しています。
(C99、6.5p2)「は前と次のシーケンスポイントとの間のオブジェクトが格納された値は、式の評価によって、せいぜい一度変更したものとする。
単純割り当てならびに化合物割り当ては、シーケンスポイントを導入していない。ここでシーケンスポイントが式文式の前と式文の後にあります。
シーケンスポイントはC99とC11規格の附属書C(参考)に記載されています。
^=は、シーケンスポイントではありません、彼らは彼らではない
です。
実際には未定義の動作ですか?
はいです。この "賢い"技法を使わないでください。
確認していただきありがとうございます。心配しないで、私は最初にそれを使うつもりはありませんでした。 – Medinoc
この式にシーケンスポイントがないため、未定義の動作が発生します。
あなたは自明それを修正し、がはシーケンスポイントを導入しないコンマ演算子を使って、簡潔のほとんどを維持できます。
a ^= b, b ^= a, a ^= b;
この時点で3つの異なる行に置くこともできます。 – Thomas
^=
オペレータの評価の順序が明確に定義されています。明確に定義されていないのは、a
とb
が変更された順序です。
a ^= b ^= a ^= b;
は、その引数が評価される前に、オペレータは評価できない
a ^= (b ^= (a ^= b));
に相当し、間違いなく最初a ^= b
を実行しようとしています。
これを未定義の動作にする理由は、コンパイラに最適化の柔軟性を与えるために、任意の順序で変数値を変更できることです。コンパイラは唯一のものを行うには、これらの3つの方法のいずれかを選択することができれば
int a1 = a^b;
int b1 = b^a1;
int a2 = a^b1;
a = a2;
a = a1;
b = b1;
、:
int a1 = a^b;
int b1 = b^a1;
int a2 = a^b1;
a = a1;
a = a2;
b = b1;
またはこの:
int a1 = a^b;
int b1 = b^a1;
a = a1;
int a2 = a^b1;
a = a2;
b = b1;
かさえ、このことは、これを行うために選択することができますこれは単に「不特定」の動作になります。しかし、標準はさらに進んで、これを "未定義"の動作にしています。これは、コンパイラが基本的にそれが起こり得ないと仮定できるようにします。
最初の説明は究極ですが、理由を理解できませんでした:* '変更前または変更後の値' * –
これは誤解を招くようなものです。評価が既に完了した後、式の副作用が起きるのを防ぐものは何もありません。 'a^= b'の結果は' a^b'であり、副作用として 'a'がその結果に設定されます。 * 'a'がその結果に設定されているときは、指定されていません。特に、外側の 'a^= = ... 'が始まる前に終了する必要があるものは何もありません。 – hvd
@hvd:私は同意します。私はそれを明確にするために言い換えようとしました。 –
何が起こっているのかを示すのが難しいコードを書く場合は、将来の開発者が理解できるようにもっと簡単な方法があれば自分自身に尋ねてください。 –
C++コードでこれを見た場合、C++では、Cで定義されていない特定の構造体(これについてはわかりません)を許可する代入演算子のルールが異なります。 – hvd
[Sequence Point - Xor配列の入れ替えが間違った結果になる](http://stackoverflow.com/questions/9958514/sequence-point-xor-swap-on-array-get-wrong-result) –