i = ++i + 1
最近、やのようなクレイジーでありながら構文的に許可されているコード ステートメントの出力について、多くの質問が寄せられるのを見てきましたi=(i,i++,i)+1;
。率直に言って、実際のプログラミングでそのようなコードを書く人はほとんどいません。したがって、私は通常、ここでそのような質問をスキップしてしまいます。しかし、最近、そのような Q が非常に多く聞かれるので、そのような Q を飛ばすことで重要な理論を見逃しているのではないかと考えさせられます。そのようなQは を中心に展開していると思いSequence points
ます。率直に言って、シーケンス ポイントについてはほとんど何も知りません。誰かが理論/概念を説明してもらえますかSequence points
、または可能であれば、概念について説明しているリソースを示します。また、この概念/理論について知るために時間を費やす価値はありますか?
5 に答える
私が考えることができる最も簡単な答えは次のとおりです。
C++ は、抽象マシンの観点から定義されています。抽象マシンで実行されるプログラムの出力は、「副作用」が実行される順序に関してのみ定義されます。また、副作用は IO ライブラリ関数の呼び出しとして定義され、volatile とマークされた変数への変更が行われます。
C++ コンパイラは、コードを最適化するために内部的に必要なことは何でも実行できますが、揮発性変数への書き込みの順序と io 呼び出しを変更することはできません。
シーケンス ポイントは、c/c++ プログラムのハートビートを定義します。シーケンス ポイントの前の副作用は「完了」し、シーケンス ポイントの後の副作用はまだ発生していません。ただし、副作用 (または、間接的に副作用に影響を与える可能性のあるコード) は、シーケンス ポイント内で並べ替えることができます。
そのため、それらを理解することが重要です。その理解がなければ、C++ プログラムとは何か (および積極的なコンパイラによってどのように最適化されるか) についての基本的な理解に欠陥があります。
はい、シーケンスポイントの正確な技術的詳細は厄介になる可能性があります。しかし、これらのガイドラインに従うと、ほとんどすべての実際的な問題が解決されます。
- 式が値を変更する場合、変更とその値の他の使用との間にシーケンスポイントが存在する必要があります。
- 値の2つの使用法がシーケンスポイントで区切られているかどうかわからない場合は、コードをさらに多くのステートメントに分割してください。
ここでの「変更」には=
、、+=
など++x
の左側の値に対する代入演算と、、、、、および構文が含まれます。(通常、これらのインクリメント/デクリメント式で、巧妙になり、問題が発生する場合があります。)x++
--x
x--
幸いなことに、ほとんどの「予想される」場所にはシーケンスポイントがあります。
- すべてのステートメントまたは宣言の最後。
- すべての関数呼び出しの開始時と終了時。
- ビルトイン
&&
と||
オペレーターで。 - 三
?
項式で。 - 組み込みの
,
コンマ演算子で。(たとえば、条件で最も一般的に見られfor (a=0, b=0; a<m && b<n; ++a, ++b)
ます。)関数の引数を区切るコンマは、コンマ演算子ではなく、シーケンスポイントでもありません。
、、をオーバーロードoperator&&
し、シーケンスポイントを発生operator||
させoperator,
ません。その事実からの潜在的な驚きは、それらを過負荷にすることが通常推奨されない理由の1つです。
http://en.wikipedia.org/wiki/Sequence_pointを参照してください。
これは非常に単純な概念なので、多くの時間を投資する必要はありません:)
シーケンスポイントが存在することを知っておく価値があります。なぜなら、シーケンスポイントについて知らなければ、テストでは正常に実行されるように見えますが、実際には未定義であり、別のコンピューターまたは異なるコンパイルオプションで実行すると失敗する可能性があるコードを簡単に記述できるからです。x++
特に、たとえば、を含むより大きな式の一部として記述した場合、x
問題が発生しやすくなります。
すべてのルールを完全に学ぶ必要はないと思いますが、仕様を確認する必要がある場合、またはおそらくより良い場合は、シーケンスポイントに依存しないようにコードを書き直す必要がある場合を知る必要があります。より単純な設計でも機能するかどうかのルール。
int n,n_squared;
for(n=n_squared=0;n<100;n_squared+=n+ ++n)
printf("%i squared might or might not be %i\n",n,n_squared);
... 思った通りの結果が得られるとは限りません。これにより、デバッグが困難になる可能性があります。その理由は、++n が n の値を取得、変更、および格納するためです。これは、n が取得される前または後に行われる可能性があります。したがって、n_squared の値は、最初の反復後に明確に定義されていません。シーケンス ポイントは、部分式が順番に評価されることを保証します。