【循环语句】

一. while

提出问题
  • while语句用什么指令进行跳转的呢?答:jmp,je指令
  • 在哪个地方存放这条指令呢?
C++
ListNode* deleteDuplicates(ListNode* head) {
    if (!head) {
        return head;
    }
    ListNode* cur = head;
    while (cur->next) {
        if (cur->val == cur->next->val) cur->next = cur->next->next;
        else cur = cur->next;
    }
    return head;
}

设计实验:

int main()
{
    int* pWorth = NULL;
    while (pWorth)
    {
        std::cout << "有意义";
    }
}

汇编

mov         dword ptr [ebp-4],0  
cmp         dword ptr [ebp-4],0  
je          00871026  
push        873138h  
mov         eax,dword ptr ds:[00873068h]  
push        eax  
call        008710B0  
add         esp,8  
jmp         0087100B

当执行完第二行的cmp指令后,ZF位的值改变了,说明ZF影响je指令是否会跳转

在这里插入图片描述

发现规律
  • 当ZF为1,je指令会被执行,使EIP的值改变,从而跳转到指定的内存地址;当ZF为0,je指令只会使EIP寄存器+2;
知识点:
  • ZF位:零标志位,代表指令运算的结果为零时会设置为1,代表了两个数是否相等
得出结论
  • while语句的本质是mov , cmp, je, jmp指令的组合
  • jmp指令的作用是跳到while语句的首地址,以实现重复执行指令
  • je指令的作用是跳转到jmp指令后面的的地址,避免死循环的结果,需要与cmp指令,mov指令配合使用
  • 注意点:while代码块里面的代码中必须要有让循环退出的数据或break语句,否则会使程序进入****死循环状态

在这里插入图片描述

二.do{}while()
猜测:该语句也有cmp,je,mov指令,只不过跟jmp指令放在了一起
C++
int main()
{
	int* pWorth = NULL;
	do
	{
	    std::cout << "有意义";
	}while (pWorth == NULL);
}
汇编
00791002 in          al,dx  
00791003 push        ecx  

00791004 mov         dword ptr [ebp-4],0  
 
0079100B push        793138h  
00791010 mov         eax,dword ptr ds:[00793068h]  
00791015 push        eax  
00791016 call        007910B0  
0079101B add         esp,8  
 
0079101E cmp         dword ptr [ebp-4],0  
00791022 je          0079100B  
  
00791024 xor         eax,eax  
00791026 mov         esp,ebp  
00791028 pop         ebp  
00791029 ret
发现规律:

do while 语句是由cmp指令,跳转指令(jne,je)组合而成的,而跳转的地址是代码块的首地址

得出结论:
  • do while 代码块里面的指令必须要有改变判断变量值的代码或break语句,否则会造成程序的死循环
    在这里插入图片描述

三. for(){}

提出问题:
  • 在括号里的变量i为什么在for循环外不能使用?
  • i++指令什么地方执行呢?猜测:在jmp指令后面 答案:
  • 第一个分号前的代码会被多次执行吗?
C++
vector<int> twoSum(vector<int>& nums, int target){
    vector<int> ret;
    for (int i = 0; i < nums.size(); i++)
    {
        for (int y = i + 1; y < nums.size(); y++)
        {
            if (nums[i] + nums[y] == target) {
                ret.push_back(i);
                ret.push_back(y);
                break;
            };
        }
    }
    return ret;
}

0x0 从 汇编的角度去看for语句

jae指令

ZF = 0时,CF = 0时时,jae指令会跳转到对应的内存地址
ZF = 1时,CF = 0时时,jae指令会跳转到对应的内存地址
ZF = 0时,CF = 1时时,jae指令会使EIP+2

得出结论
  • for语句由以下模块组成的汇编指令, 第一次执行指令到i++,会跳过直接比较
  • 当程序符号条件就进行重复执行指令阶段,直到数据不符合条件为止,因此代码块里必须有让条件不符合的数据break语句
  • for循环第一次执不会执行i++,会JMP到比较指令,根据比较结果决定是否执行代码块,然后才会执行i++,再进行判断;这是for循环的特点,设计的时候需要考虑索引值的问题

在这里插入图片描述

0x1 从设计的角度去看for语句

红色线条的思考:循环过程需要用到的局部变量初始值是什么呢?
蓝色线条的思考:每一次的跳转需要我们去做什么样的重复行为呢?
黑色线条的思考:第一次的跳转以后的跳转需要我们分别去做什么样的比较行为呢?
第一个方框内容的思考:循环过程需要不断做的操作是什么呢?

应用场景:
内存里的某个变量的值不在某个值范围时,要反复去执行同一段指令

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值