ネタ元>ちょっとしたクイズです
Rさんが問題を出していますが…実はこれ、根が深いですよ…。
ということで、私も問題。
言語はC#です。
int i;
i = 0; var a = i * i++;
i = 0; var b = i * ++i;
i = 0; var c = i++ * i;
i = 0; var d = ++i * i;
a, b, c, dの値を答えてください。
C言語とC#だと結果が変わってきます。
それに、C言語の場合、i = i * i++; と書いてしまうと未定義動作です。
この動作は、C# だとどうなっているのか調べてみました。
7.2 演算子 (C#)
>式のオペランドは、左から右に評価されます。
>これは、演算子の優先順位とは異なるものであり、関係ありません。
つまり、前置インクリメントであれ、後置インクリメントであれ、
インクリメントの左にある場合は古い値、右にある場合は新しい値として評価されます。
そして、i *= 10;のような複合代入の場合です。
これは、i = i * 10; と展開されるため、常に古い値として評価された値との演算になります。
結果的に想定通りの答えだとしても、意外に難しい問題です。
また、調べていたらこんなものを発見しました。
7.4.1 引数リスト (C#)
こちらで紹介されているサンプルソースです。
var i = 0;
foo (i++, i++, i++);
これも、C言語ではやはり未定義と呼ばれているものですね。
C言語だと、引数の順序をどのように評価してもいいし、またi++が3回呼ばれるかどうかすら定かではありません。
しかし、C#は正確に前から評価していくみたいなので、この呼び出しは、foo(0, 1, 2); と等価なのだそうです。
この関数を呼び終わった後のiの値は、当然3です。
このあたりのC言語では未定義だったゾーンがC#ではきっちりきまっているみたいです。