• 用汇编的眼光看C++(之循环流程) 四


    【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】


        循环是我们编程中遇到的另外一项重要技术。通过反复的迭代运算,我们可以获取想要的任何结果。当然这种迭代是有基本条件的,或是以时间为条件的,或是以空间为条件的,或者是某一种外来交互作为条件的。循环的方式有很多种,但是常用的还是:while、for、do-while、goto这几种。很多公司的项目都不喜欢goto,这其中倒不是说goto不好,主要是goto的随意性太大,一旦用的不好,就会降低代码的可读性,反而影响其他人的工作效率。

        (1)do-while为什么先执行,后判断?

        老规矩,我们还是先看代码示例再说:

    1. 21:       int m = 10;  
    2. 00401638   mov         dword ptr [ebp-4],0Ah  
    3. 22:       do {  
    4. 23:           printf("%d\n", m);  
    5. 0040163F   mov         eax,dword ptr [ebp-4]  
    6. 00401642   push        eax  
    7. 00401643   push        offset string "%d\n" (0046f01c)  
    8. 00401648   call        printf (00420fb0)  
    9. 0040164D   add         esp,8  
    10. 24:           m ++;  
    11. 00401650   mov         ecx,dword ptr [ebp-4]  
    12. 00401653   add         ecx,1  
    13. 00401656   mov         dword ptr [ebp-4],ecx  
    14. 25:       }while(m < 10);  
    15. 00401659   cmp         dword ptr [ebp-4],0Ah  
    16. 0040165D   jl          process+1Fh (0040163f)  
        如果换成while呢?

    1. 21:       int m = 10;  
    2. 00401638   mov         dword ptr [ebp-4],0Ah  
    3. 22:       while(m < 20)  
    4. 0040163F   cmp         dword ptr [ebp-4],14h  
    5. 00401643   jge         process+41h (00401661)  
    6. 23:       {  
    7. 24:           printf("%d\n", m);  
    8. 00401645   mov         eax,dword ptr [ebp-4]  
    9. 00401648   push        eax  
    10. 00401649   push        offset string "%d\n" (0046f01c)  
    11. 0040164E   call        printf (00420fb0)  
    12. 00401653   add         esp,8  
    13. 25:           m ++;  
    14. 00401656   mov         ecx,dword ptr [ebp-4]  
    15. 00401659   add         ecx,1  
    16. 0040165C   mov         dword ptr [ebp-4],ecx  
    17. 26:       }  
    18. 0040165F   jmp         process+1Fh (0040163f)  
    19. 27:   }  
        其实,上面的代码表现已经很明显了。do-while的时候,模块上来先进行运算,然后再判断数据范围的大小;while就不一样,上来就进行判断,判断成功就继续运行,否则就退出循环模块,如果是for的情况呢?

    1. 21:       for(int m = 10; m < 20; m++)  
    2. 00401638   mov         dword ptr [ebp-4],0Ah  
    3. 0040163F   jmp         process+2Ah (0040164a)  
    4. 00401641   mov         eax,dword ptr [ebp-4]  
    5. 00401644   add         eax,1  
    6. 00401647   mov         dword ptr [ebp-4],eax  
    7. 0040164A   cmp         dword ptr [ebp-4],14h  
    8. 0040164E   jge         process+4Ch (0040166c)  
    9. 22:       {  
    10. 23:           printf("%d\n", m);  
    11. 00401650   mov         ecx,dword ptr [ebp-4]  
    12. 00401653   push        ecx  
    13. 00401654   push        offset string "%d\n" (0046f01c)  
    14. 00401659   call        printf (00420fc0)  
    15. 0040165E   add         esp,8  
    16. 24:           m ++;  
    17. 00401661   mov         edx,dword ptr [ebp-4]  
    18. 00401664   add         edx,1  
    19. 00401667   mov         dword ptr [ebp-4],edx  
    20. 25:       }  
    21. 0040166A   jmp         process+21h (00401641)  
        我们发现,其实for和上面的while,do-while有点小区别。在m第一次赋值的时候,并不进行加1处理,而是直接跳到地址0x40164a处运行,判断m数值和20进行判断。判断成功,则跳入循环模块,否则越过循环模块。那么,在循环处理结束后呢?也就是m++后,循环模块是怎么处理的?我们发现代码又回到了0x00401641处处理。但是这里并不是整个循环模块开始出的代码,而是对m进行自增处理。完成自增后,继续判断,下面的流程和第一次一样,不再赘述。


        (2)多重循环怎么跳出来?

        很多朋友编码的时候都有这样的一个困扰,有的时候希望在多层循环中寻找某一个条件的变量,但是在找到特定变量后,希望赶快退出循环。我们应该怎么做呢,下面是我个人的做法,仅供大家参考。

    1. int flag = 0;   
    2.        for(int m = 1; m < 20 && !flag; m++)  
    3. {  
    4.     for(int n = 1; n < 20 && !flag; n++)  
    5.     {  
    6.         for(int t = 1; t < 20 && !flag; t++)  
    7.         {  
    8.             if(/* special conditions are satisfied */)  
    9.                 flag = 1;  
    10.         }  
    11.     }  
    12. }  


        (3)while(1)是否有其他的表示方法?

    1. int flag = 0;  
    2. for(;;) {  
    3.     /* code segment */  
    4. }  
    5.   
    6. do{  
    7.     /* code segment */  
    8. }while(1);  
    9.   
    10.  loop:  
    11. {  
    12.     /* code segment */  
    13. }  
    14.   
    15. if(!flag)  
    16.     goto loop;  

    总结:

        其实,循环中还有很多的细节需要处理,你比如说:

        (1)循环的时候请务必填上程序终止的条件

        (2)循环的时候注意8位char和32和int之间的区别,务必不要死循环

        (3)字符的循环务必注意‘\0’

        (4)不要把循环、判断合二为1,给你的同事留条活路,不要以为while(*dst ++  = *src ++);这样写代码很帅

        (5)务必注意自己的返回值是你需要的那个地址,还是前一个地址,还是下一个地址

         (6)不要在for(;;)中添加额外的语句,加的越多,风险越多

        

  • 相关阅读:
    Openstack API 开发 快速入门
    virtualBox虚拟机到vmware虚拟机转换
    使用Blogilo 发布博客到cnblogs
    Openstack Troubleshooting
    hdoj 1051 Wooden Sticks(上升子序列个数问题)
    sdut 2430 pillars (dp)
    hdoj 1058 Humble Numbers(dp)
    uva 10815 Andy's First Dictionary(快排、字符串)
    sdut 2317 Homogeneous squares
    hdoj 1025 Constructing Roads In JGShining's Kingdom(最长上升子序列+二分)
  • 原文地址:https://www.cnblogs.com/sier/p/5676494.html
Copyright © 2020-2023  润新知