C Language
シーケンスポイント
サーチ…
備考
国際標準ISO / IEC 9899:201xプログラミング言語 - C
揮発性オブジェクトにアクセスする、オブジェクトを変更する、ファイルを変更する、またはこれらの操作のいずれかを行う関数を呼び出すことは、実行環境の状態の変化である副作用です。
式AとBの評価の間のシーケンスポイントの存在は、Aに関連するすべての値の計算および副作用が、Bに関連するすべての値の計算および副作用の前に順序付けられることを意味する。
C言語標準のオンライン2011プレリリース草案附属書Cのシーケンスポイントの完全なリストを以下に示します 。
シーケンスポイント
1 5.1.2.3で説明したシーケンスポイントは次のとおりです。
- ファンクションコールの実際の引数とファンクションデジグネータの評価の間。 (6.5.2.2)。
- 次の演算子の第1オペランドと第2オペランドの評価の間:論理AND
&&
(6.5.13);論理OR||
(6.5.14);コンマ,
(6.5.17)。- 条件付きの最初のオペランドの評価の間
? :
第2オペランドと第3オペランドのどちらかが評価される(6.5.15)。- 完全な宣言者の終わり:宣言者(6.7.6);
- 完全な式の評価と評価される次の完全な式の間。以下は完全な式です:複合リテラル(6.7.9)の一部ではない初期化子。式文(6.8.3)の式。選択文の制御式(
if
またはswitch
)(6.8.4);while
文またはdo
文の制御式(6.8.5)。for
文(6.8.5.3)の(オプションの)各式。return
文(6.8.6.4)の(オプションの)式。- ライブラリ関数が返る直前(7.1.4)。
- 書式化された各入出力関数変換指定子(7.21.6,7.29.2)に関連付けられたアクションの後。
- 比較関数への各呼び出しの直前および直後、および比較関数への呼び出しと、その呼び出しに引数として渡されたオブジェクトの移動(7.22.5)との間にも存在します。
シーケンス式
次の式が順序付けられています 。
a && b
a || b
a , b
a ? b : c
for ( a ; b ; c ) { ... }
すべての場合において、式a
は完全に評価され、 b
またはc
いずれかが評価される前にすべての副作用が適用されます。 4番目のケースでは、 b
またはc
1つのみが評価されます。最後のケースでは、 b
が完全に評価され、 c
が評価される前にすべての副作用が適用されます。
全ての場合において、式の評価a
の評価の前に配列決定されb
又はc
(交互の評価b
及びc
評価後に配列決定されています)。 a
したがって、
x++ && x++
x++ ? x++ : y++
(x = f()) && x != 0
for ( x = 0; x < 10; x++ ) { ... }
y = (x++, x++);
よく定義された振る舞いを持つ。
順序付けられていない式
次の式は順序付けされていません 。
a + b;
a - b;
a * b;
a / b;
a % b;
a & b;
a | b;
上記の例では、式の前に評価され得るか、または発現後にa
b
、 b
前に評価することができる、またはそれらは、いくつかの命令に対応する場合、それらはさらに混合されてもよいです。 a
関数呼び出しについても同様の規則が適用されます。
f(a, b);
ここでないだけとa
b
unsequenced(すなわちされ,
関数呼び出しのオペレータがシーケンスポイントを生成しない )だけでなく、 f
、呼び出される関数を決定する式。
副作用は、評価の直後に適用されてもよく、後の時点まで延期されてもよい。
式のような
x++ & x++;
f(x++, x++); /* the ',' in a function call is *not* the same as the comma operator */
x++ * x++;
a[i] = i++;
または
x++ & x;
f(x++, x);
x++ * x;
a[i++] = i;
未定義の動作を起こす
- オブジェクトの変更およびそれに対する他のアクセスは、順序付けされなければならない
- 副作用 1が適用される評価順序および順序は規定されていない。
1実行環境の状態の変更。
不確定に配列された式
f(a)
ような関数呼び出しは、常に引数の評価と指定子(ここではf
とa
)と実際の呼び出しの間のシーケンスポイントを意味します。 2つの呼び出しが順序付けされていない場合、2つの関数呼び出しは不確定に順序付けられています。つまり、一方が他方の前に実行され、順序が指定されていません。
unsigned counter = 0;
unsingned account(void) {
return counter++;
}
int main(void) {
printf("the order is %u %u\n", account(), account());
}
printf
引数の評価中にこの暗黙的に2倍のcounter
変更counter
ことは有効です。どの呼び出しが最初に来るのか分かりません。注文は不特定であるため、それは変わる可能性があり、依存することはできません。したがって、プリントアウトは次のようになります。
順序は0 1です
または
注文は1 0です
中間関数呼び出しを使用せずに上記と同様のステートメント
printf("the order is %u %u\n", counter++, counter++); // undefined behavior
counter
2つの変更の間にシーケンスポイントがないため、未定義の動作があります。