研究の対象
例として、2つの異なる言語(CおよびC#)で式「
++i + ++i
」の操作を分析します。 ご存じのとおり、1つ目はネイティブプロセッサコードにコンパイルされ、2つ目は大まかに言えば仮想スタックマシンに基づいて動作します。 したがって、例自体を検討してください。
Cのソース:
- #include <stdio.h>
- void main()
- {
- int i = 5;
- i = ++ i + ++ i;
- printf( "%d \ n" 、i);
- }
C#のソース:
- システムを使用して ;
- パブリック クラステスト
- {
- public static void Main()
- {
- int i = 5;
- i = ++ i + ++ i;
- Console .WriteLine(i);
- }
- }
Cスクリーンの後ろ
逆アセンブラを使用して、Cコンパイラが最終的に生成したものを見てみましょう。
#A#5:int i = 5; cs:0295 BE0500 mov si、0005 #A#6:i = ++ i + ++ i; cs:0298 46 inc si cs:0299 46 inc si cs:029A 8BC6 mov ax、si cs:029C 03C6 add ax、si cs:029E 8BF0 mov si、ax #A#7:printf( "%d \ n"、i); cs:02A0 56プッシュsi cs:02A1 B8AA00 mov ax、00AA cs:02A4 50プッシュa cs:02A5 E8330C call _printf
リストからわかるように、コンパイラーは変数
i
を
x86
SI
レジスターにマップしました。 その後、このレジスターを2回インクリメントし、
AX
バッテリーを介して自分自身に追加しました。 その結果、変数
i
は14に等しくなります。
C#画面の背後
Ildasmを使用して、 C#の背後にあるものを見てみましょう。
.method public hidebysig static void Main()cil managed { .entrypoint //コードサイズ21(0x15) .maxstack 3 .locals init(int32 V_0) IL_0000:ldc.i4.5 // 5 5をプッシュ IL_0001:stloc.0 // i:= pop()null IL_0002:ldloc。0 // iiをプッシュ IL_0003:ldc.i4.1 // 1 i、1をプッシュ IL_0004:add // push(pop()+ pop())(i + 1)つまり 6 IL_0005:dup //スタックの先頭をコピー6、6 IL_0006:stloc。0 // i:= pop()// i:= 6 6 IL_0007:ldloc。0 // i 6、iをプッシュ IL_0008:ldc.i4.1 // 1 6、i、1をプッシュ IL_0009:add // push(pop()+ pop())6、(i + 1)つまり 7 IL_000a:dup //スタックの先頭をコピー6、7、7 IL_000b:stloc。0 // i:= pop()// i:= 7 6、7 IL_000c:add // push(pop()+ pop())13 IL_000d:stloc.0 // i:= pop()null IL_000e:ldloc。0 // iiをプッシュ IL_000f:void [mscorlib] System.Consoleを呼び出す:: WriteLine(int32) IL_0014:ret } //メソッドテストの終わり::メイン
明確にするために、アセンブラーの仮想スタックマシンにコメントを追加しました。 リストを見ると、変数
i
をインクリメントするために、変数自体と変数がスタックにプッシュされていることがわかります。 次に、スタックから2つの値を取得して追加する追加コマンドが実行され、結果がスタックに戻されます。 次に、スタックの先頭を複製し、変数に値を書き戻します。 したがって、
5 + 1
スタックに残ります。 6.次に、別の増分でサイクルが繰り返されます。変数がスタックにプッシュされ、続いてユニット、追加、頂点の複製が発生し、2番目の増分の結果が変数に書き戻されます。
i
は7があり、最初のケースから6つ、2番目から7つがスタックに残ります。 次に、追加コマンドが実行され、結果が13になり、変数に入力されます。
まとめ
ここにそのような同一のものがあります、コードは異なる条件で完全に異なって実行されます。 プログラムではこの種のコードを避けてください。
トピックが興味深いと思われる場合-お知らせください。編集の世界から興味深い瞬間をいくつか書きます。
UPD コメントは、 PHP 、 Java 、 Actionscript 3 、 JavaScriptおよびTCLでは結果も13ですが、 Perl 、 K ++およびCではGCCは14であることを示唆しています (ただし、GCCの結果はオプティマイザ設定に依存する場合があります):)
PL / SQLとPython -10は区別されています(K.O.が示唆しているように-言語に増分がないため) -Bash -12。
また、このようなコードの作成を許可しないコンパイラもあります。 たとえば、 Ruby (またはそのような)。
そして、あなたの%username%コンパイラの結果はどうなりますか?
UPD2 。 関連リンク: ウィキペディアのフォローポイント、 Alyona C ++ 。