2015-09-30 11 views
5

呼び出し前にpの値が が5に初期化されている場合、f(p、p)の戻り値は何ですか?最初のパラメータは であり、2番目のパラメータは値渡しであることに注意してください。与えられたコードでは未定義の動作ですか?

int f (int &x, int c) { 
     c = c - 1; 
     if (c==0) return 1; 
     x = x + 1; 
     return f(x,c) * x; 
} 

オプションは次のとおりです。


私が説明しよう:このコードで


、4つの再帰的なパラメータを持つコール(6,4)、(7,3)、(8,2)と(9,1)が存在します。最後の呼び出しは1を返します。しかし、参照渡しにより、前のすべての関数のxは9になります。したがって、f(p、p)によって返される値は9 * 9 * 9 * 9 * 1 = 6561になります。


この質問は競争試験GATE(see Q.no.-42)からのものです。答えキーはGATEの "すべてにマークする"(正しいオプションがないことを意味します)key set-C, Q.no.-42です。どこかに説明されています:

GATE 2013では、C/C++の同じコードがすべて未定義の動作を生成するため、マークが付けられました。これは、*がC/C++のシーケンスポイントではないためです。正しいコードは

res = f(x,c); 
return res * x; 

return f(x,c) * x; 

を交換する必要がありますが、与えられたコードが正常に動作します。ゲートの鍵は間違っていますか?それとも本当に間違いですか?

+2

あなたが両方の方法を見ずに通りを渡ると起こることの1つは、相手側に安全に行うことです。しかし、両道を見ずに通りを横切る人が安全に反対側にそれを作ることを*予測することは誤りです。 –

+0

[Sequence Point ambiguity、Undefined behavior?](http://stackoverflow.com/q/29513572/1708801)と似ています –

答えて

14
return f(x,c) * x; 

この操作の結果は、2つのものが評価される順序によって異なります。あなたが評価される順序を予測することはできないので、この操作の結果を予測することはできません。

+0

なぜここでうまくいくの?[this-code](http://cpp.sh/8m6y) –

+5

@ user4791206「うまくいく」とはどういう意味ですか?それが何をするのか予測できないので、なぜそれがうまくいっているのだろうと言うでしょうか?それを予測した人は、他の順序で評価すると、うまくいったとは言えませんでしたか? –

+0

評価順序の問題は、定義されていない動作です[I-read](http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points)? –

9

C++ 03章5:

指摘し、個々の事業者との個別 表現の部分式のオペランドの評価、および副作用が行われる順番の順序は、指定されていない場合を除き。

のでf(x,c) * xの場合には、オペランドの評価順序は、左または右のオペランドが最初に評価を取得するかどうか、あなたが知ることができないことを意味し、指定されていません。

コードにの指定されていない動作があります。これはコンパイラにのみ知られている特定の定義された方法で動作することを意味します。プログラマは、コードが何をするのかを知ることはできません。最初に左のオペランドを最初に評価するか、最初に右のオペランドを評価するだけです。コンパイラは、最適化のためにケースバイケースで評価の順序を変更することさえ可能です。

評価の順序が重要な場合は、コードを書き直す必要があります。不特定の動作に依存するコードは、常にバグであり、おそらく非常に微妙なものであり、直ちに現れません。

未定義の振る舞いは未定義の振る舞いとは異なります。これは、予定外の振る舞いやクラッシュなど、何かが起こる可能性があることを意味します。

+2

補足として、同じテキストはC++ 11では異なっていますが、同じ意味を持っています。私はC++ 11(とC11)は、テキストを理解するのをもっと難しくしていたと思います。なぜ古いバージョンの標準を引用していますか? – Lundin

+0

ありがとうございました。 –

+0

一般に、「不特定の動作」は、プログラマがコードが何をするかを知ることができないことを意味するのではなく、プログラマがどのような場合にコンパイラが選択する可能性のある動作を知ることができないことを意味する。可能なすべてのコンパイラ動作の組み合わせがプログラマの要件を満たす場合、プログラマはプログラムが正しく動作することを期待する権利があります。コンパイラが何らかの選択をしても動作する限り、定義されたアクションの中から不特定の方法で選択するコンパイラに依存するコードには何も問題はありません。 – supercat

関連する問題