请问为什么下面代码输出的值为22?求给出分析过程
#include<stdio.h> int main(void) { int i=5,j=5; int p; p=(++i)+(++i)+(++i); printf("p=%d",p); return 0; }
欢迎选择我的课程,让我们一起见证您的进步~~
同じ変数に対する複数の ++ の評価順序は不確かです。この動作は 未定義 です。このようなコードは、副作用を伴うコードを作成することをお勧めします。 評価順についてはwikiを参照してください
これが試験問題である場合は、関連する試験資料を参照してください。
C++11/14 および C11 の正しい考え方は次のとおりです。
式 (++i)+(++i)+(++i) に関連する順序付けルールは、インクリメント優先順序付けルール (副作用は値の前に計算されます) と演算子の順序付けルール (オペランドの値は演算子の結果の値が計算される前に計算されます) です。計算済み)。
(++i)+(++i)+(++i)
これによって決定できる計算順序: この式では、関連する ++i の値が計算される前に、任意の + の副作用と値が計算されます (+ には副作用はありません) ) とその副作用は値の前に計算されます (つまり、最初に増加します)。 + の結合性 (左から右) によると、最初の + の値が 2 番目の + の値が計算される前に計算されると結論付けることができます。
++i
+
計算順序が決定不能: 値の計算と 2 つの ++i の副作用との間に明確な順序関係はありません。
直感的には、上記の制限に基づいて、可能な一連の計算プロセスをリストすることができます。
6+7+8 = 13+86+8+7 = 14+77+6+8 = 13+8...
しかし、問題は、C++11/14 標準には次の規則があることです:
(§1.9/15)[...]スカラー オブジェクトの副作用が、同じスカラー オブジェクトの別の副作用、または同じスカラー オブジェクトの値を使用した値の計算に対して順序付けされていない場合、動作は未定義です。
C11 標準には次の規則があります:
(§6.5/2) スカラー オブジェクトの副作用が、同じスカラー オブジェクトの別の副作用、または同じスカラー オブジェクトの値を使用した値の計算に対して順序付けされていない場合、動作は次のようになります。未定義。[...]
この式内の 2 つの '++i' の間の副作用の順序は未定であるため、これは C++11/14 および C11 では未定義の動作になります。
C++11 および C11 より前のルールについてはここでは説明しませんが、その標準によれば、これらも未定義の動作です。
最後の冗長な文は未定義の動作です。 C++11 標準には次の規則があります:
(§1.3.24) 未定義の動作この国際規格が要件を課していない動作[注: この国際規格が動作の明示的な定義を省略している場合、または未定義の動作が予期される場合があります。プログラムが誤った構造または誤ったデータを使用する場合、許容される未定義の動作は、予測できない結果をもたらす状況を完全に無視することから、環境に特有の文書化された方法での変換またはプログラムの実行中の動作 (診断メッセージの発行の有無にかかわらず)、変換または実行を終了します (診断メッセージの発行を伴う)。多くの誤ったプログラム構成は、診断が必要な未定義の動作を引き起こしません。 C11 標準には次の規則があります
(§1.3.24) 未定義の動作この国際規格が要件を課していない動作[注: この国際規格が動作の明示的な定義を省略している場合、または未定義の動作が予期される場合があります。プログラムが誤った構造または誤ったデータを使用する場合、許容される未定義の動作は、予測できない結果をもたらす状況を完全に無視することから、環境に特有の文書化された方法での変換またはプログラムの実行中の動作 (診断メッセージの発行の有無にかかわらず)、変換または実行を終了します (診断メッセージの発行を伴う)。多くの誤ったプログラム構成は、診断が必要な未定義の動作を引き起こしません。
(§3.4.3)1 未定義の動作移植性のない、または誤ったプログラム構成または誤ったデータの使用時の動作。この国際規格では要件を課していません2 注考えられる未定義の動作は、状況を完全に無視して予期しない結果をもたらすものから、翻訳またはプログラムの実行中にその環境に特徴的な文書化された方法で動作する (診断メッセージの発行の有無にかかわらず)、翻訳または実行を終了する (診断メッセージの発行あり) まで多岐にわたります。診断メッセージの)。
つまり、標準では未定義の動作に関する要件は設けられておらず、コンパイラーまたは実行プラットフォームは、コンパイル時または実行時に未定義の動作の動作について合意するかどうかに関係なく、合意することができます。規約がなければ、プログラムの動作はまったく予測できなくなります。
Tan Ye の (霧) のアイデアに従うと、(おそらく) 演算子 + (左の組み合わせ) の組み合わせに基づいて、同等の式 ((++i)+(++i))+(++i) が得られます。次に、左側の 2 つの ++i が最初に計算される (濃い霧) ため、それらは (7+7)+(++i) に相当し、これは (7+7)+8 (大きなもの) に等しいと推定されます。 22。
((++i)+(++i))+(++i)
(7+7)+(++i)
(7+7)+8
22
問題は、結合方法が部分式の値が評価される順序とは何の関係もないことです。
操作に参加した最初の ++i の結果は 6、操作に参加した 2 番目の ++i の結果は 7 となり、同様に 3 番目の ++i の結果も 7 になります。演算は 8 なので、最初の 2 つは 8 になり、最終結果は 24 になります。私は VS を使用しており、これは C++ で測定されています。
VSも同様で、Cを使った結果は以下の通りです
上記の回答は正しいので、回答を撤回させていただきました。
この問題にどうしても対処したい場合は、使用しているコンパイラのアセンブリにコードをコンパイルして、正確に何が起こるかを確認してください
@lianera の回答に同意します。この種の操作 C 言語標準では、操作の統一された順序が規定されていません。
うーん。 。ここまで言っておきますが、実際のところ、問題は計算順序ではまったくありません。 加算演算の順序は左から右です。
p=(++i)+(++i)+(++i);
初めて追加すると、一見 6+7 のように見えますが、2 番目の ++i の自己インクリメントにより、その前に i(6) が来ます (最初の ++i です)。 ) も 7 になります。そうすると、最初のステップの合計は 14 になります。
次に、3 番目の i (8) を 14 に加算すると、22 となります。
この答えは SX の教科書にのみ適しています。実際に使用すると足が折れてしまいます。もちろん、さまざまなコンパイラでも式が提供されます。
同じ変数に対する複数の ++ の評価順序は不確かです。この動作は 未定義 です。このようなコードは、副作用を伴うコードを作成することをお勧めします。
評価順についてはwikiを参照してください
これが試験問題である場合は、関連する試験資料を参照してください。
C++11/14 および C11 の正しい考え方は次のとおりです。
式
(++i)+(++i)+(++i)
に関連する順序付けルールは、インクリメント優先順序付けルール (副作用は値の前に計算されます) と演算子の順序付けルール (オペランドの値は演算子の結果の値が計算される前に計算されます) です。計算済み)。これによって決定できる計算順序: この式では、関連する
++i
の値が計算される前に、任意の+
の副作用と値が計算されます (+
には副作用はありません) ) とその副作用は値の前に計算されます (つまり、最初に増加します)。+
の結合性 (左から右) によると、最初の+
の値が 2 番目の+
の値が計算される前に計算されると結論付けることができます。計算順序が決定不能: 値の計算と 2 つの
++i
の副作用との間に明確な順序関係はありません。直感的には、上記の制限に基づいて、可能な一連の計算プロセスをリストすることができます。
6+7+8 = 13+8
6+8+7 = 14+7
7+6+8 = 13+8
...
しかし、問題は、C++11/14 標準には次の規則があることです:
C11 標準には次の規則があります:
この式内の 2 つの '++i' の間の副作用の順序は未定であるため、これは C++11/14 および C11 では未定義の動作になります。
C++11 および C11 より前のルールについてはここでは説明しませんが、その標準によれば、これらも未定義の動作です。
最後の冗長な文は未定義の動作です。 C++11 標準には次の規則があります:
つまり、標準では未定義の動作に関する要件は設けられておらず、コンパイラーまたは実行プラットフォームは、コンパイル時または実行時に未定義の動作の動作について合意するかどうかに関係なく、合意することができます。規約がなければ、プログラムの動作はまったく予測できなくなります。
Tan Ye の (霧) のアイデアに従うと、(おそらく) 演算子 + (左の組み合わせ) の組み合わせに基づいて、同等の式
((++i)+(++i))+(++i)
が得られます。次に、左側の 2 つの++i
が最初に計算される (濃い霧) ため、それらは(7+7)+(++i)
に相当し、これは(7+7)+8
(大きなもの) に等しいと推定されます。22
。問題は、結合方法が部分式の値が評価される順序とは何の関係もないことです。
操作に参加した最初の ++i の結果は 6、操作に参加した 2 番目の ++i の結果は 7 となり、同様に 3 番目の ++i の結果も 7 になります。演算は 8 なので、最初の 2 つは 8 になり、最終結果は 24 になります。私は VS を使用しており、これは C++ で測定されています。
VSも同様で、Cを使った結果は以下の通りです
上記の回答は正しいので、回答を撤回させていただきました。
この問題にどうしても対処したい場合は、使用しているコンパイラのアセンブリにコードをコンパイルして、正確に何が起こるかを確認してください
@lianera の回答に同意します。この種の操作 C 言語標準では、操作の統一された順序が規定されていません。
うーん。 。ここまで言っておきますが、実際のところ、問題は計算順序ではまったくありません。 加算演算の順序は左から右です。
p=(++i)+(++i)+(++i);
初めて追加すると、一見 6+7 のように見えますが、2 番目の ++i の自己インクリメントにより、その前に i(6) が来ます (最初の ++i です)。 ) も 7 になります。そうすると、最初のステップの合計は 14 になります。
次に、3 番目の i (8) を 14 に加算すると、22 となります。
この答えは SX の教科書にのみ適しています。実際に使用すると足が折れてしまいます。もちろん、さまざまなコンパイラでも式が提供されます。