5.7 do/while/for的比较(1)
VC++(www.cppentry.com)使用三种语法来完成循环结构,分别为为do、while、for。虽然它们完成的功能都是循环,但是每种语法有着不同的执行流程。
do循环:先执行循环体,后比较判断。
while循环:先比较判断,后执行循环体。
for循环:先初始化,再比较判断,最后执行循环体。
对每种结构进行分析,了解它们生成的汇编代码,它们之间的区别,以及如何根据每种循环结构的特性进行还原。
(1)do循环
do循环的工作流程清晰,识别起来也相对简单。根据其特性,先执行语句块,再进行比较判断。当条件成立时,会继续执行语句块。C++(www.cppentry.com)中的goto语句也可以用来模拟do循环结构,如代码清单5-21所示。
代码清单5-21 使用goto语句模拟do循环
- // goto模拟do循环完成正数累加和
- int GoToDo(int nCount){
- int nSum = 0;
- int nIndex = 0;
- // 用于goto语句跳转使用标记
- GOTO_DO:
- // 此处为循环语句块
- nSum += nIndex; // 保存每次累加和
- nIndex++; // 指定循环步长为每次递增1
- // 若nIndex大于nCount,则结束goto调用
- if (nIndex <= nCount){
- goto GOTO_DO;
- }
- return nSum; // 返回结果
- }
代码清单5-21演示了使用goto语句与if分支结构来实现do循环过程。程序执行流程是自上向下地顺序执行代码,通过goto语句向上跳转修改程序流程,实现循环。do循环结构也是如此,如代码清单5-22所示。
代码清单5-22 do循环—Debug版
- // C++(www.cppentry.com)源码说明:do循环完成整数累加和
- int LoopDO(int nCount){
- int nSum = 0;
- int nIndex = 0;
- do {
- nSum += nIndex;
- nIndex++;
- // 循环判断,是否结束循环体
- } while(nIndex <= nCount);
- return nSum;
- }
-
- // C++(www.cppentry.com)源码与对应汇编代码讲解
- // C++(www.cppentry.com)源码对比,变量初始化
- int nSum = 0;
- 0040B4D8 mov dword ptr [ebp-4],0
- int nIndex = 0;
- 0040B4DF mov dword ptr [ebp-8],0
- // C++(www.cppentry.com)源码对比,进入循环语句块
- do{
- nSum += nIndex;
- ; 循环语句块的首地址,即循环跳转地址
- 0040B4E6 mov eax,dword ptr [ebp-4]
- 0040B4E9 add eax,dword ptr [ebp-8]
- 0040B4EC mov dword ptr [ebp-4],eax
- nIndex++;
- 0040B4EF mov ecx,dword ptr [ebp-8]
- 0040B4F2 add ecx,1
- 0040B4F5 mov dword ptr [ebp-8],ecx
- // C++(www.cppentry.com)源码对比,比较是否结束循环
- } while(nIndex <= nCount);
- 0040B4F8 mov edx,dword ptr [ebp-8]
- ; 比较两个内存中的数据
- 0040B4FB cmp edx,dword ptr [ebp+8]
- ; 根据比较结果,使用条件跳转指令JLE,小于等于则跳转到地址0x0040B4E6处
- 0040B4FE jle LoopDO+26h (0040b4e6)
- return nSum;
- 0040B500 mov eax,dword ptr [ebp-4]
代码清单5-22中的循环比较语句“while(nIndex <= nCount)”转换成的汇编代码和if分支结构非常相似,分析后发现它们并不相同。if语句的比较是相反的,并且跳转地址大于当前代码的地址,是一个向下跳转的过程;而do中的跳转地址小于当前代码的地址,是一个向上跳转的过程,所以条件跳转的逻辑与源码中的逻辑相同。有了这个特性,if语句与do循环判断就很好区分了。
总结:
- DO_BEGIN:
- …… ; 循环语句块
- ; 影响标记位的指令
- jxx DO_BEGIN ; 向上跳转