7

これは未定義の動作であることを理解しています:

int i = 0;
int a[4];
a[i] = i++;  //<--- UB here

i左側と右側のの評価順序が定義されていないためです (;が唯一のシーケンス ポイントです)。

その推論をさらに一歩進めると、これは次のようになると私には思えます未定義未指定の動作:

int i = 0;

int foo(){
    return i++;
}

int main(){
    int a[4];
    a[i] = foo();
    return 0;
}

の右側にいくつかのシーケンスポイントがありますが、=私が理解している限りではまだです未定義またはが最初に評価されるかどうf()かは指定されていません。a[i]

私の仮定は正しいですか?代入の左側でグローバル変数または静的変数を使用し、右側がそれを変更しない場合、細心の注意を払う必要がありますか?

4

2 に答える 2

6
a[i] = foo();

ここでは、 または が最初に評価されるかどうかは指定されていません。新しい C++11 の表現では、2 つの評価は順序付けされていません。ただし、それだけでは未定義の動作は発生しません。それは、同じスカラー オブジェクトへの 2 つの順不同のアクセスがあり、そのうちの少なくとも 1 つが書き込みである場合です。それがUBである理由です。fooa[i]a[i] = i++;

これら 2 つのステートメントの違いは、への呼び出しがfoo()シーケンス ポイントを導入することです。C++11 の表現は異なります。呼び出された関数内の実行は呼び出し関数内の他の評価に対して不定に順序付けられます。

a[i]これは、とi++内部の間に半順序があることを意味しfooます。その結果、 or のいずれa[0]a[1]が 0 に設定されますが、プログラムは適切に定義されています。

于 2014-04-08T15:07:59.123 に答える
1
a[i] = i++;

の値は 2 つのシーケンス ポイント間で変更およびアクセスされるため、これは未定義の動作ですi(また、アクセスは の次の値の計算には直接関与しませんi)。評価の順序が指定されていないため、これも指定されていない動作です ( のインクリメントは、 へのインデックスとしてi使用する前後に発生する可能性があります)。ia

次のような関数呼び出しを導入する場合:

a[i] = foo();

関数呼び出しは、さらに 2 つのシーケンス ポイントを導入します。1 つは関数に入る前、もう 1 つは関数が戻った後です。

これはi、関数内のインクリメントが 2 つのシーケンス ポイントで囲まれ、未定義の動作を引き起こさないことを意味します。

i関数呼び出しが割り当ての左側のインデックスとして使用される前に行われるか、または使用された後に行われるかは、まだ未規定の動作です。

于 2014-04-08T15:07:29.903 に答える