次のコードでこの出力が生成されるのはなぜですか。
コードスニペット:
int a=10;
printf("%d%d%d",++a,a++,++a);
出力:
131113
パラメータはどのように評価されますか? これはコンパイラに依存しますか?gccコンパイラを使用しています。私のコンパイラがそれをどのように評価したか誰か教えてもらえますか? コンパイラが関数のパラメータを右から左に評価する場合、このコードの出力は次のようになります。
121111
次のコードでこの出力が生成されるのはなぜですか。
コードスニペット:
int a=10;
printf("%d%d%d",++a,a++,++a);
出力:
131113
パラメータはどのように評価されますか? これはコンパイラに依存しますか?gccコンパイラを使用しています。私のコンパイラがそれをどのように評価したか誰か教えてもらえますか? コンパイラが関数のパラメータを右から左に評価する場合、このコードの出力は次のようになります。
121111
それが未定義の動作です。シーケンス ポイントで変数を複数回変更することは、未定義の動作です。
ウィキから:
シーケンス ポイントは、以前の評価のすべての副作用が実行され、後続の評価の副作用がまだ実行されていないことが保証される、コンピューター プログラムの実行の任意のポイントを定義します。
読んでください:演算子の優先順位と評価の順序
完全に理解するには、未定義の動作とシーケンス ポイントをお読みください。
ただし、これを行うことができます:
int a=10;
int b = (++a,a++,++a);
カンマ (,) はここでは演算子であり、printf
.
これは実際には未規定の動作と未定義の動作の両方の組み合わせです。
関数の引数の評価の順序が指定されていないため、この行では指定されていません。
printf("%d%d%d",++a,a++,++a);
^ ^ ^ ^
1 2 3 4
1
関数の引数がどの順序で評価されるかはわかりません。4
これがループ内にあった場合、後続の実行で順序が異なる可能性さえあります。これは、C99 ドラフト標準セクション6.5.2.2
関数呼び出しパラグラフ10で説明されています (強調鉱山):
関数指定子、実引数、および実引数内の部分式の評価順序は指定されていませんが、実際の呼び出しの前にシーケンス ポイントがあります。
これ自体は、プログラムの出力が信頼できないことを意味しますが、上記のコードが 1 つのシーケンス ポイント内で複数回変更されるため、未定義の動作もあります。これは、式の段落2のセクションで説明されています(強調鉱山):a
6.5
前のシーケンス ポイントと次のシーケンス ポイントの間で、オブジェクトの格納値は、式の評価によって最大 1 回変更されます。72)さらに、以前の値は、保存する値を決定するためにのみ読み取られるものとします。73)
未定義の動作とは、正しく動作しているように見えることを含め、このプログラムを実行すると何らかの結果が生じる可能性があることを意味します。この用語はセクションで定義されており、未定義の動作の可能性のある結果を説明する3.4.3
次の注記が含まれています。
未定義の可能性のある動作は、状況を完全に無視して予測不能な結果をもたらすことから、翻訳中またはプログラム実行中に環境に特有の文書化された方法で動作すること (診断メッセージの発行の有無にかかわらず)、翻訳または実行の終了 (診断メッセージの発行を伴う) にまで及びます。診断メッセージの)。
それを超えて、信頼できる結果コードを取得できたとしても、そのようなコードは読みにくく、複雑なプロジェクトで維持するのは悪夢です。パフォーマンスなどの他の要件を満たすコードを作成する別の簡単な方法がある場合は、それが取るべきアプローチです。