使用C++,还是了解点底层比较好~:)[续1]

本文深入探讨C++的基础结构,包括循环结构(For-loop、While-loop、Do-while-loop)、Switch结构及if-else判断等内容,并通过逆向工程揭示了这些结构在底层的实际表现形式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

          上次做了同事出的题目以后突然萌发了一个想法,那就是趁着这个机会对C++做一次新的体验(再学习),这次我打算从底层来探究C++的实质,并且用实时操作的手法澄清在现实工作和学习中对于C++难点的误解[注:实验环境--XpSP2简体中文版+VS2003英文版+SP1],首先我还是打算从最最基本的东西开始,今天就研究一下C++程序基本结构的问题【这次超级基础,下次将从函数、类开始分析了】,例如三种循环结构、Switch结构、if-else的判断等等,文章末尾我还想将一些容易被误导的问题做一个澄清,如:A+=B 是否真的是相当于A = A + B 的问题,还有++p,p++的问题等等。

         首先,来看看我们在C++程序中常用的几种结构:

1、循环结构A: For-Loop

     For-loop几乎是使用频度最高的一个循环了,For-loop循环结构清晰过程明朗,是遍历搜索必备佳品:)

     下面是一个典型的For-loop【For-loop的变种也可以如此分析】:

     for( int nIdx = 0; nIdx < 1000; ++nIdx) //附注:其实这里nIdx++与++nIdx的效果是一样的,其汇编编译都是一样的,并没有孰快孰慢的问题

    {

         ..............//循环体部分

    } 

   我们来看看它的底层实现【为了方便起见,本着使用工具最少原则,仅用VS2003逆向在Debug状态下分析,Release状态下做了优化不方便理解问题,有兴趣的朋友可以用OD(OllyDbg)或许更为好理解】:

004112CE  mov         dword ptr [ebp-30h],0 //将nIdx初始化为零
004112D5  jmp          004112E0 //跳转到地址0X004112E0
004112D7  mov         eax,dword ptr [ebp-30h] //将nIdx的值放入累加寄存器
004112DA  add         eax,1 //将累加寄存器里的值+1
004112DD  mov        dword ptr [ebp-30h],eax //将EAX的值赋回nIdx
004112E0  cmp         dword ptr [ebp-30h],3E8h //将nIdx的值与1000比较
004112E7  jge           004112EB //大于或等于1000则跳出循环(循环Break)

............ //循环体部分

004112E9  jmp         004112D7 //调往地址0X004112D7,继续做++nIdx操作。

2.循环结构B:   While-loop

     while-loop也是在平时使用比较多的一个循环语句,特别在强调循环条件的时候常用到。

     int nIdx = 0;

     while( nIdx < 1000 )

    {

        .............//循环体中语句

        ++nIdx;

    }

逆向后:

00411309  mov         dword ptr [ebp-3Ch],0//初始化nIdx为0

00411310  cmp         dword ptr [ebp-3Ch],3E8h //将nIdx与1000比较
00411317  jge         00411324  //大于或者等于的时候跳往地址0X00411324(亦即循环Break,跳出循环)

..........//循环体中语句

//以下三条指令就是++nIdx,也是nIdx++

00411319  mov         eax,dword ptr [ebp-3Ch]
0041131C  add         eax,1
0041131F  mov         dword ptr [ebp-3Ch],eax

00411322  jmp         00411310 //跳往比较位置地址

3.循环结构C:Do-while-loop 这个结构我记得好像《Code Complete2》里面是不推荐使用的,可控性不好,容易出错,同时也可以被上面两个循环代替。

    int nIdx = 0;

    do

   {

      ..........

       ++nIdx;

   }while( nIdx < 1000 )

逆向后【貌似指令数量还要少些哦,速度快些?比For-loop少了两个跳转指令,比while-loop少一个】:

00413009  mov         dword ptr [ebp-3Ch],0  初始化nIdx为0

...........//循环语句

// ++nIdx;
00413010  mov         eax,dword ptr [ebp-3Ch]
00413013  add         eax,1
00413016  mov         dword ptr [ebp-3Ch],eax

00413019  cmp         dword ptr [ebp-3Ch],3E8h  //nIdx与1000比较
00413020  jl          00413010 //若小于则跳往循环语句(这里循环语句为空的,所以就跳向自增了)

4.switch结构

  int nCase = 0;

  switch( nCase )

{

   case 0:

         ......

         break;

    case 1:

         ......

         break;

    default:

         ......

         break;

}

逆向后:

 int nCase = 0;
00413022  mov         dword ptr [ebp-48h],0 //nCase赋初值为0;
 switch(nCase)
00413029  mov         eax,dword ptr [ebp-48h] //将nCase的值放入累加寄存器中
0041302C  mov         dword ptr [ebp+FFFFFEF0h],eax //将EAX里的值放入switch自己生成的临时变量中去(注意这个变量在switch语句中的值是不会变的!(废话:)))
00413032  cmp         dword ptr [ebp+FFFFFEF0h],0 //与0比较
00413039  je          00413046 若等则跳转到case0 对应的语句地址
0041303B  cmp         dword ptr [ebp+FFFFFEF0h],1 //与1比较
00413042  je          00413076  若等则跳到case1对应的语句的地址
00413044  jmp         004130A4跳往Default情况对应语句的位置

OK,粗略分析了一下基本结构【if-then-else结构忽略,可以参照以上分析进行】,接下来看看一个容易搞错的问题,就是A += B,是否真的总是A = A + B呢?

就先看两种情况吧(其他的情况碰到了自己分析一下,原理一样:))

  int nA = 1;

  int nB = 2;

  nA += nB;

  nA = nA + nB;

逆向看看先:

  int nA = 1;
00412FAC  mov         dword ptr [ebp-30h],1
 int nB = 2;
00412FB3  mov         dword ptr [ebp-3Ch],2
 nA += nB;
00412FBA  mov         eax,dword ptr [ebp-30h]
00412FBD  add         eax,dword ptr [ebp-3Ch]
00412FC0  mov         dword ptr [ebp-30h],eax
 nA = nA + nB;
00412FC3  mov         eax,dword ptr [ebp-30h]
00412FC6  add         eax,dword ptr [ebp-3Ch]
00412FC9  mov         dword ptr [ebp-30h],eax

的确一样哦!

但是看看这个呢:

int szNum[5] = { 1, 2, 3, 4, 5 };
00412F4E  mov         dword ptr [ebp-18h],1
00412F55  mov         dword ptr [ebp-14h],2
00412F5C  mov         dword ptr [ebp-10h],3
00412F63  mov         dword ptr [ebp-0Ch],4
00412F6A  mov         dword ptr [ebp-8],5
 int *ptrA = szNum;
00412F71  lea         eax,[ebp-18h]
00412F74  mov         dword ptr [ebp-24h],eax

 *(ptrA++) += 100;
00412F77  mov         eax,dword ptr [ebp-24h]
00412F7A  mov         ecx,dword ptr [eax]
00412F7C  add         ecx,64h
00412F7F  mov         edx,dword ptr [ebp-24h]
00412F82  mov         dword ptr [edx],ecx
00412F84  mov         eax,dword ptr [ebp-24h]
00412F87  add         eax,4
00412F8A  mov         dword ptr [ebp-24h],eax
  
 *(ptrA++) = *(ptrA++) + 100;
00412F8D  mov         eax,dword ptr [ebp-24h]
00412F90  mov         ecx,dword ptr [eax]
00412F92  add         ecx,64h
00412F95  mov         edx,dword ptr [ebp-24h]
00412F98  mov         dword ptr [edx],ecx
00412F9A  mov         eax,dword ptr [ebp-24h]
00412F9D  add         eax,4
00412FA0  mov         dword ptr [ebp-24h],eax
00412FA3  mov         ecx,dword ptr [ebp-24h]
00412FA6  add         ecx,4
00412FA9  mov         dword ptr [ebp-24h],ecx

过程不用说了吧~,++p,p++的情况一样分析:),下次就到函数里面去看看,再下次就进入C++对象模型了,看看类的具体实现,再再下次......to be continued.

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值