14

C99 §6.5

(1) 式は、値の計算を指定するか、オブジェクトまたは関数を指定するか、副作用を生成するか、またはそれらの組み合わせを実行する一連の演算子とオペランドです。

(2) 前のシーケンス ポイントと次のシーケンス ポイントの間で、オブジェクトの格納値は、式の評価によって最大 1 回変更されます。72)さらに、以前の値は、保存する値を決定するためにのみ読み取られるものとします。73)

脚注付き

72) 浮動小数点状態フラグはオブジェクトではなく、式内で複数回設定できます。

73) この段落は、次のような未定義のステートメント式をレンダリングします。

    i = ++i + 1;
    a[i++] = i;

許可しながら

    i = i + 1;
    a[i] = i;

ここで、C11 §6.5 は次のように変更されました ((1) のテキストには補遺があります):

(1) […] 演算子のオペランドの値の計算は、演算子の結果の値の計算の前に並べられます。

(2) スカラー オブジェクトに対する副作用が、同じスカラー オブジェクトに対する別の副作用または同じスカラー オブジェクトの値を使用した値の計算と比較して順序付けされていない場合、動作は未定義です。式の部分式に複数の順序付けが許可されている場合、いずれかの順序付けでそのような順序付けされていない副作用が発生した場合の動作は未定義です。84)

ここで、C11 の脚注 84 は C99 の脚注 73 と同じです。

私は少し混乱しています… C11 (2) を「[…] (同じスカラー オブジェクトに対する異なる副作用) または (同じスカラー オブジェクトの値を使用した値の計算) […]」のように読みます。許可さえしませんfoo = ++i(副作用があり、変更されたオブジェクトに応じて値を使用します)。ただし、私はネイティブ スピーカーではないので、この文をどのように「解析」する必要があるか教えていただければ幸いです。C99 は理解できますが、C11 の文言はよくわかりません。

とにかく、実際の質問: これは C99 から C11 への変更ですか、それともこれらの文言は同等ですか? もしそうなら、なぜ変更されたのですか?そうでない場合、誰かが C99 では UB であるが C11 では UB ではない、またはその逆の式の例を挙げてもらえますか?

4

4 に答える 4

5

C11 (および C++11) では、シーケンシングの文言が完全に作り直されました。これは、C11 がスレッドを持つようになったためであり、同じデータにアクセスするスレッド間のシーケンシングが何を意味するかを説明する必要がありました。委員会の意図は、実行スレッドが 1 つしかない場合に備えて、C99 との後方互換性を維持することでした。

C99 バージョンを見てみましょう。

  1. 前のシーケンス ポイントと次のシーケンス ポイントの間

  2. オブジェクト

  3. 持つものとします

  4. 保存された値は最大で 1 回変更されます

  5. 式の評価によって。

新しいテキストに比べて

に副作用があれば

4 の別の用語、保存された値の変更

スカラー オブジェクト

2 の以前の文言の制限。新しいテキストは、スカラー オブジェクトについて何かを述べているだけです。

どちらに対しても順序付けされていません

unsequenced は、1. の概念を一般化したものです。2 つのステートメントはシーケンス ポイントで区切られています。ロックなどを使用せずに同じデータを変更する 2 つのスレッドを考えてみてください。

同じスカラー オブジェクトに対する別の副作用

オブジェクトは一度だけ変更できます

または、同じスカラー オブジェクトの値を使用した値の計算、

または、値の読み取りが変更と同時に表示されない場合があります

動作は未定義です。

3.の「しなければならない」は、これを暗黙のうちに言っています。すべての「shall」が満たされない場合、UB につながります。

于 2014-01-11T20:07:15.067 に答える
3

私は少し混乱しています… C11 (2) を「[…] (同じスカラー オブジェクトに対する異なる副作用) または (同じスカラー オブジェクトの値を使用した値の計算) […]」のように読みます。許可さえしませんfoo = ++i(副作用があり、変更されたオブジェクトに応じて値を使用します)。

標準見積書をよく読むと

スカラー オブジェクトに対する副作用が、同じスカラー オブジェクトに対する別の副作用または同じスカラー オブジェクトの値を使用した値の計算と比較してシーケンス化されていない場合、動作は未定義です式の部分式に複数の順序付けが許可されている場合、いずれかの順序付けでそのような順序付けされていない副作用が発生した場合の動作は未定義です。84)

次に、あなたの言葉遣いが次のようであるべきであることがわかります:

スカラー オブジェクトに対する副作用が、(同じスカラー オブジェクトに対する別の副作用) または (同じスカラーオブジェクトの値を使用した値の計算)に対して順序付けされていない場合。

これfoo = ++iは、定義されたステートメントであることを意味します。ion (on にfooも)副作用があることは事実ですが、ここでは object に対してunsequencediは何もありません。

于 2014-01-11T19:56:12.317 に答える
2

これは説明ですfoo = ++iが、実際には質問に対する答えではありません。


プレフィックスの増分は、複合割り当てに関して定義されます。6.5.3/2 を参照してください。

++Eは次と同等です(E+=1)

一般的な割り当てについては、6.5.16/3 に保証があります。

左オペランドの格納された値を更新する副作用は、左オペランドと右オペランドの値の計算の後に順序付けられます。オペランドの評価は順不同です。

Sofoo = ++iは と同等foo = (i+=1)です。内部は、計算後に順序付けされるようにi+=1変更する必要があります。式の結果の値は、6.5.16/3 で次のように指定されています。ii+1(i+=1)

代入式は、代入後に左オペランドの値を持ちますが、左辺値ではありません。

これには、 の変更後にの値の計算を順序付けする必要があるように思われます。C++11 では、これは明示的に保証されています [expr.ass]/1i+=1i

いずれの場合も、代入は、右オペランドと左オペランドの値の計算の後、代入式の値の計算の前に順序付けされます。

(これは私には明らかですが、C++ は C よりもはるかによく知っています)

の変更はiの値の計算の前に順序付けられるため、 の値にi+=1アクセスする UB はありません( の左オペランドと右のオペランドの値の計算はの変更の前に順序付けられるため)。++ifoo = ++ifoo = xfoo

于 2014-01-11T19:23:29.633 に答える
1

私が理解している限りでは、

スカラー オブジェクトに対する副作用が... に対して順序付けされていない場合、同じスカラー オブジェクトの値を使用した値の計算

(1) は次のことを述べているため、ここでは適用されません。

演算子のオペランドの値の計算は、演算子の結果の値の計算の前に並べられます。

言い換えれば、結果は「後で来る」ように定義されます。つまり、順序付けされます

于 2014-01-11T19:54:18.483 に答える