問題タブ [sequence-points]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c - C で関数を呼び出すときのシーケンス ポイントと未定義/未指定の動作
C のシーケンス ポイントについての理解を深めようとしています。何かを確認したかっただけです。g
現在、(1) は未定義であるのに対し、(2) は単に指定されていないと考えています。(2) では、 andの引数を評価した後にシーケンス ポイントが存在することに基づいています (したがって、シーケンス ポイント間で 2 回h
変更することはありません)。i
ですが、 の引数の評価順序f
はまだ指定されていません。私の理解は正しいですか?
編集:
ここでの重要なポイントは、コンパイラがどちらかの前に両方のインクリメントを自由に実行できるかどうか、g
またはh
呼び出されるかどうかです.
c++ - 「a[i]=i++;」のようなインクリメント操作を行うのはなぜですか。未定義の動作になりますか?
重複の可能性:
未定義の動作とシーケンスポイント
コードパッドは私にこれを与えています:9行目:警告:「i」の操作が未定義である可能性がありますなぜ操作が未定義なのですか?
c++ - シーケンスポイントはどこから来ますか?
私は次のようなものを書いていることを知っています
読めないだけでなく、c/c++ シーケンス ポイントにも違反しています。
これらの制限はどこから来るのでしょうか? それらをバグとして見つける前に、これらの「問題」をどのように見ることができますか?
c - i = post_increment_i() の動作は、指定されているか、指定されていないか、または未定義ですか?
次の C プログラムを考えてみましょう。
C 標準の 2011 年版 (C11 として知られる) に関して、次の代替案のうち正しいものはどれですか。
- C11 は、main が 0 を返すことを保証します。
- C11 は、main が 0 または 1 を返すことを保証します。
- このプログラムの動作は、C11 に従って未定義です。
C11 標準からの関連スニペット:
5.1.2.3 プログラムの実行
揮発性オブジェクトへのアクセス、オブジェクトの変更、ファイルの変更、またはこれらの操作のいずれかを行う関数の呼び出しはすべて、実行環境の状態の変化である副作用です。一般に、式の評価には、値の計算と副作用の開始の両方が含まれます。左辺値式の値の計算には、指定されたオブジェクトの ID の決定が含まれます。
前に順序付けされるのは、単一のスレッドによって実行される評価間の非対称で推移的なペアワイズ関係であり、これらの評価間に部分的な順序が生じます。任意の 2 つの評価 A と B が与えられた場合、A が B の前に配列されている場合、A の実行は B の実行よりも前に実行されます (逆に、A が B の前に配列されている場合、B は A の後に配列されます)。 B の前または後に、A と B は順序付けされていません。評価 A と B は、A が B の前または後にシーケンスされる場合、不定にシーケンスされますが、どちらが指定されていません。13式 A と B の評価の間にシーケンス ポイントが存在することは、A に関連付けられたすべての値の計算と副作用が、B に関連付けられたすべての値の計算と副作用の前に並べられることを意味します。 .)
13) 順序付けられていない評価の実行はインターリーブできます。不確定な順序の評価はインターリーブできませんが、任意の順序で実行できます。
6.5 式
式は、値の計算を指定するか、オブジェクトまたは関数を指定するか、副作用を生成するか、またはそれらの組み合わせを実行する一連の演算子とオペランドです。演算子のオペランドの値の計算は、演算子の結果の値の計算の前に並べられます。
スカラー オブジェクトに対する副作用が、同じスカラー オブジェクトに対する別の副作用または同じスカラー オブジェクトの値を使用した値の計算と比較してシーケンス化されていない場合、動作は未定義です。式の部分式に複数の許容される順序付けがある場合、順序付けのいずれかでそのような順序付けされていない副作用が発生した場合、動作は未定義です。
6.5.2.2 関数呼び出し
関数指定子と実際の引数の評価の後、実際の呼び出しの前に、シーケンス ポイントがあります。呼び出された関数の本体の実行の前後に特に順序付けされていない呼び出し側関数 (他の関数呼び出しを含む) 内のすべての評価は、呼び出された関数の実行に関して不定に順序付けられます。94
94) 言い換えれば、関数の実行は互いに「インターリーブ」しません。
6.5.2.4 後置インクリメントおよびデクリメント演算子
後置 ++ 演算子の結果は、オペランドの値です。副作用として、オペランド オブジェクトの値がインクリメントされます (つまり、適切な型の値 1 がそれに追加されます)。[...]結果の値の計算は、オペランドの格納された値を更新する副作用の前に順序付けられます。不定順序の関数呼び出しに関しては、後置 ++ の操作は単一の評価です。
6.5.16 割り当て
代入演算子は、左オペランドで指定されたオブジェクトに値を格納します。[...] 左オペランドの格納された値を更新する副作用は、左オペランドと右オペランドの値の計算の後に順序付けられます。オペランドの評価は順不同です。
6.8 ステートメントとブロック
完全な式は、別の式または宣言子の一部ではない式です。次のそれぞれは完全な式です: [...] 式ステートメント内の式。[...] return ステートメントの (オプションの) 式。完全な式の評価と、次に評価される完全な式の評価の間には、シーケンス ポイントがあります。
上記の 3 つの選択肢は、それぞれ次の 3 つのケースに対応します。
- 後置インクリメント演算子の副作用は、メインの割り当ての前に並べられます。
- 後置インクリメント演算子の副作用は、メインの代入の前または後のいずれかに配列され、C11 はどちらを指定しません。(つまり、2 つの副作用の順序は不定です。)
- 2 つの副作用は順序付けられていません。
次の一連の推論により、最初の選択肢が成り立つようです。
呼び出された関数の本体の実行の前または後に特に順序付けされていない呼び出し側関数 (他の関数呼び出しを含む) 内のすべての評価は、呼び出された関数の実行に関して不定に順序付けられるという規則を考慮してください。6.5.2.2。仮定 A: main の代入演算子の副作用は、このような「評価」です。仮定 B: 「呼び出された関数の実行」という句には、後置インクリメント演算子の値計算と後置インクリメント演算子の副作用の両方が含まれます。これらの仮定と上記のルールから、I) 値の計算と後置インクリメント演算子の副作用の両方がメインの代入演算子の副作用の前に並べられるか、II) 値の計算と副作用後置インクリメント演算子の両方が、メインの代入演算子の副作用の後に並べられます。
ルールを考慮してください。左側のオペランドの格納された値を更新する副作用は、左側と右側のオペランドの値の計算の後に順序付けられます。このルールは、上記のケース I を除外します。したがって、ケース II が成立します。QED
全体として、これはかなり強力な議論のように見えます。また、これは、直感的に考えられる最も可能性の高い代替案に対応しています。
ただし、「評価」および「呼び出された関数の実行」という用語の特定の解釈 (仮定 A および B) と、完全に単純ではない推論に依存しているので、人々がこの解釈が間違っていると信じる理由。脚注 94 は、呼び出し元が呼び出し先とインターリーブしないという意味でも適用される場合にのみ、この解釈と同等であることに注意してください。これは、「インターリーブ」が「abab」の意味でのインターリーブを意味することを意味します。弱い「アバ」の意味での呼び出し先。また、i = i++
c - 「x=x ++」のようなものでVSまたはXcodeの警告を取得するにはどうすればよいですか?
「x=++ x」などのシーケンスポイントに関連付けられた未定義の動作の精神では、それは本当に未定義ですか?、どのようにしてコンパイラにそのようなコードについて文句を言わせるのですか?
具体的には、私はVisual Studio2010とXcode4.3.1を使用しています。後者はOSXアプリ用ですが、どちらもこれについて警告していません。VS2010の警告を「すべて」に上げて、これをうまくコンパイルしました。(記録として、VS2010のバージョンは変数に1を追加しましたが、Xcodeのバージョンは変数を変更しませんでした。)
c - GCC におけるポストインクリメント、関数呼び出し、シーケンス ポイントの概念
GCC が予期しない結果を生成するコード フラグメントがあります。
(ターゲット i686-linux-gnu には gcc バージョン 4.6.1 Ubuntu/Linaro 4.6.1-9ubuntu3 を使用しています)
[test.c]
私の理解では、関数呼び出しにシーケンス ポイントがあります。後置インクリメントは、f() の前に実行する必要があります。
C99 5.1.2.3 を参照してください: 「... シーケンス ポイントと呼ばれ、以前の評価のすべての副作用は完全であり、後続の評価の副作用は発生していません。」
このテスト ケースでは、評価の順序が指定されていない可能性がありますが、最終結果は同じになるはずです。したがって、b の最終結果は 5 であると予想されます。しかし、このケースを 'gcc test.c -std=c99' でコンパイルした後、出力は b = 3 を示します。
次に、「gcc test.c -std=c99 -S」を使用して何が起こったかを確認します。
GCC は f() の前に評価された値を使用し、2 回の f() 呼び出しの後に '++' 操作を実行するようです。
また、llvm-clang を使用してこのケースをコンパイルすると、結果は b = 5 と表示されます。これは予想どおりです。
ポストインクリメントとシーケンスポイントの動作に関する私の理解は間違っていますか?? それとも、これは GCC461 の既知の問題ですか??
c - 次の式の動作は明確に定義されていますか?
次の式のシーケンス ポイントを考慮します。
私が正しければ、実行の手順は次のようになります。
1)
2)
3)
ステップ 1 の評価では、コンストラクトを定義済みと呼ぶには、i の値を 1 回だけ変更する必要があります (コンマ演算子の評価後にシーケンス ポイントがあるため)。しかし、ここではそうではないと思います。したがって、未定義にする必要があります。この回答をご覧ください。ここでは、上記の式を定義済みと呼びます。何か不足していますか?
c++ - シーケンスポイントと演算子の優先順位
重複の可能性:
シーケンスされていない値の計算(別名シーケンスポイント)
未定義の動作とシーケンスポイント
演算子の優先順位と評価の順序
次の式が未定義の動作をどのようにもたらすかについて、私はまだ頭を悩ませようとしています。
これについてSOを検索したところ、次の質問が見つかりました。
私はすべての答えを読み通しましたが、それでも詳細に問題があります。回答の1つは、上記のコード例の動作を、a
変更方法の観点からあいまいであると説明しています。たとえば、次のいずれかになります。
a
の変更があいまいになるのは何ですか?これは、さまざまなプラットフォームのCPU命令と関係があり、オプティマイザーが未定義の動作をどのように利用できるかを示していますか?言い換えれば、生成されたアセンブラのために未定義のように見えますか?
コンパイラが使用する理由はわかりa=(a+1);a++;
ません。奇妙に見え、あまり意味がありません。このように動作させるためのコンパイラは何を持っているでしょうか?
編集:
明確にするために、私は何が起こっているのかを理解しています。演算子の優先順位(基本的に式の評価の順序を定義する)にルールがある場合に、それがどのように未定義になるかを理解していません。この場合、割り当ては最後にa++
行われるため、割り当てる値を決定するために、最初に評価する必要がありますa
。したがって、私が期待しているa
のは、修正後の増分中に最初に変更されますが、次に割り当てる値が生成されることですa
(2番目の変更)。しかし、演算子の優先順位の規則は、動作を非常に明確にしているように見えます。未定義の動作をするための「小刻みに動く余地」がある場所を見つけることができません。
assembly - 最適化後のオブジェクトの破壊順序
さまざまな実装を比較するために、ソフトウェアでいくつかの関数呼び出しの時間を計ろうとしています。
目的のタイミングを取得するために、RAII構造体を使用して、関数の最初と最後にARMA9プロセッサのPCCNTRレジスタを読み取っています。
問題は、コンパイラがオブジェクトの構造破壊シーケンスを尊重していないことです。これはコンパイラのバグですか、それとも許可された最適化ですか?
コンパイラはarm-none-eabi-g++ (Sourcery CodeBench Lite 2012.03-56) 4.6.3
生成されたアセンブラコード:
c - コンパイラは、揮発性変数へのアクセスをシーケンス ポイントを越えて移動することはできません。どういう意味ですか?
変数を「揮発性」として宣言するということは、レジスタ変数からではなく、メモリ位置から直接読み書きすることを意味します。「シーケンスポイント」についての知識があります。しかし、私はタイトルに記載されているステートメントを理解していません。
誰かが同じことを説明して、コードスニペットも教えてもらえますか?