C++(のループフロー)をアセンブリの目で見る


【声明:著作権所有、転載歓迎、商業用途に使用しないでください.連絡ポスト:[email protected]
サイクルは私たちのプログラミングで出会ったもう一つの重要な技術です.反復演算を繰り返すことで、所望の結果を得ることができます.もちろん,この反復には基本条件があり,時間を条件としたり,空間を条件としたり,ある外来インタラクションを条件としたりする.ループの仕方はいろいろありますが、よく使われているのはwhile、for、do-while、gotoです.多くの会社のプロジェクトはgotoが好きではありません.その中でgotoが悪いというわけではありません.主にgotoの随意性が大きすぎて、いったんうまく使えないと、コードの可読性が低下し、かえって他の人の仕事の効率に影響します.
(1)do-whileはなぜ先に実行し,後で判断するのか.
古いルールですが、コードの例を見てからにしましょう.
21:       int m = 10;
00401638   mov         dword ptr [ebp-4],0Ah
22:       do {
23:           printf("%d
", m); 0040163F mov eax,dword ptr [ebp-4] 00401642 push eax 00401643 push offset string "%d
" (0046f01c) 00401648 call printf (00420fb0) 0040164D add esp,8 24: m ++; 00401650 mov ecx,dword ptr [ebp-4] 00401653 add ecx,1 00401656 mov dword ptr [ebp-4],ecx 25: }while(m < 10); 00401659 cmp dword ptr [ebp-4],0Ah 0040165D jl process+1Fh (0040163f)
whileに変えたら?
21:       int m = 10;
00401638   mov         dword ptr [ebp-4],0Ah
22:       while(m < 20)
0040163F   cmp         dword ptr [ebp-4],14h
00401643   jge         process+41h (00401661)
23:       {
24:           printf("%d
", m); 00401645 mov eax,dword ptr [ebp-4] 00401648 push eax 00401649 push offset string "%d
" (0046f01c) 0040164E call printf (00420fb0) 00401653 add esp,8 25: m ++; 00401656 mov ecx,dword ptr [ebp-4] 00401659 add ecx,1 0040165C mov dword ptr [ebp-4],ecx 26: } 0040165F jmp process+1Fh (0040163f) 27: }
実は、上のコードの表現はすでに明らかです.do-whileの場合、モジュールは先に演算を行い、データ範囲の大きさを判断します.whileは違っていて、上から判断して、成功したと判断して運転を続けます.そうしないとサイクルモジュールを終了します.forの場合ですか.
21:       for(int m = 10; m < 20; m++)
00401638   mov         dword ptr [ebp-4],0Ah
0040163F   jmp         process+2Ah (0040164a)
00401641   mov         eax,dword ptr [ebp-4]
00401644   add         eax,1
00401647   mov         dword ptr [ebp-4],eax
0040164A   cmp         dword ptr [ebp-4],14h
0040164E   jge         process+4Ch (0040166c)
22:       {
23:           printf("%d
", m); 00401650 mov ecx,dword ptr [ebp-4] 00401653 push ecx 00401654 push offset string "%d
" (0046f01c) 00401659 call printf (00420fc0) 0040165E add esp,8 24: m ++; 00401661 mov edx,dword ptr [ebp-4] 00401664 add edx,1 00401667 mov dword ptr [ebp-4],edx 25: } 0040166A jmp process+21h (00401641)
実際にはforと上のwhile,do-whileは少し違いがあることがわかりました.mが最初に値を付与する場合は、加算処理を行わずに直接アドレス0 x 40164 aにジャンプして実行し、m数値と20を判断する.成功したと判断したら、サイクルモジュールにジャンプします.そうしないと、サイクルモジュールを越えます.では、ループ処理が終わった後は?つまりm++後、サイクルモジュールはどのように処理されますか?コードはまた0 x 00401641で処理されることが分かった.しかし,ここではループモジュール全体から出るコードではなく,mを自己増分処理する.自増が完了した後、判断を続け、次の流れは初めてと同様に、余計なことは言わない.
(2)多重ループはどうやって飛び出しますか?
多くの友达が符号化する时、このような悩みがあります.时には多層サイクルの中である条件の変数を探したいと思っていますが、特定の変数を見つけたら、早くサイクルを脱退したいと思っています.私达はどのようにするべきで、以下は私の个人のやり方で、みんなの参考に供します.
	int flag = 0; 
        for(int m = 1; m < 20 && !flag; m++)
	{
		for(int n = 1; n < 20 && !flag; n++)
		{
			for(int t = 1; t < 20 && !flag; t++)
			{
				if(/* special conditions are satisfied */)
					flag = 1;
			}
		}
	}

(3)while(1)他の表示方法はありますか?
	int flag = 0;
	for(;;) {
		/* code segment */
	}

	do{
		/* code segment */
	}while(1);

  loop:
	{
		/* code segment */
	}

	if(!flag)
		goto loop;

まとめ:
実際には、サイクルには多くの詳細が必要です.例えば、
(1)サイクルの場合は必ずプログラム終了の条件を記入してください
(2)ループの場合は8位charと32とintの違いに注意し、必ずループをしない
(3)文字のループに注意してください'0'
(4)循環、判断を1にしないで、あなたの同僚に活路を残して、while(*dst+=*src++);このようにコードを書くのはかっこいいです.
(5)自分の戻り値が必要なアドレスなのか、前のアドレスなのか、次のアドレスなのかに注意してください.
(6)for(;;)にいない追加の文を追加すると、追加するほどリスクが高くなります.
    
【予報:以下、主にbreak、continue、gotoの活用について議論しますので、ご注目ください】