关闭

用汇编的眼光看C++(开篇)

发表于:2012-5-11 09:46

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:feixiaoxing    来源:51Testing软件测试网采编

  很多朋友,包括我自己在内,对C++语言的很多特性不是很明白。特别是几年前找工作的时候,为了应付来自工作单位的考试,我经常逼着自己的去记住一些复杂的试题和答案。可是常常时间已过,一切又回到了原点。原来没有弄清楚的问题还是没有弄明白,一切都没有发生改变。直到若干年后,当我在编码过程中不断积累经验,尝试用汇编代码和内存数据来解释一些现象的时候,才明白有些东西其实并不复杂。也许有的朋友对汇编语言会有畏惧,其实没有必要。只要你对C语言有一些基础,对堆栈有一些印象,那么你已经拥有汇编语言的基础了。在接下来的数篇博客中,我们就会就x86汇编、数据类型、数据运行逻辑、指针、数据、类、重载运算符在汇编下是如何展开的做一些介绍,谈一些个人的看法。下面,我们就进行一些小测试,同时用汇编语言来说明一下。大家可以一起做一下。

  (1) char name[] 和 char* name

1:
2:    void process()
3:    {
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,4Ch
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-4Ch]
0040102C   mov         ecx,13h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
4:        char name_tmp[] = {"hello"};
00401038   mov         eax,[string "hello" (0042201c)]
0040103D   mov         dword ptr [ebp-8],eax
00401040   mov         cx,word ptr [string "hello"+4 (00422020)]
00401047   mov         word ptr [ebp-4],cx
5:        char* name_glb = "hello";
0040104B   mov         dword ptr [ebp-0Ch],offset string "hello" (0042201c)
6:    }
00401052   pop         edi
00401053   pop         esi
00401054   pop         ebx
00401055   mov         esp,ebp
00401057   pop         ebp
00401058   ret

  通过上面的代码,我们可以清楚地看出两者之间的差别。"hello"字符串是一个全局只读变量,空间地址为0x0042201C。name_tmp是函数内的char数组,第4行语句下面四行表示全局数据“hello”是分两次拷贝到name_tmp的,第一次是dword、四个字节,第二次是word、两个字节。所以name_tmp共有6个字节。相比较而言,name_glb什么也没有,它只是把自己指向了全局变量而已,所以它只是一个指针而已。

  (2)apple a()和apple b

  假设class apple的定义为:

class apple
{
public:
    apple() {}
    ~apple() {}
};

  那么apple a()和apple b是分别怎么编译的呢?

9:    void process()
10:   {
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,44h
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-44h]
0040102C   mov         ecx,11h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
11:       apple a();
12:       apple b;
00401038   lea         ecx,[ebp-4]
0040103B   call        @ILT+20(apple::apple) (00401019)
13:   }
00401040   lea         ecx,[ebp-4]
00401043   call        @ILT+10(apple::~apple) (0040100f)
00401048   pop         edi
00401049   pop         esi
0040104A   pop         ebx
0040104B   add         esp,44h
0040104E   cmp         ebp,esp
00401050   call        __chkesp (004010b0)
00401055   mov         esp,ebp
00401057   pop         ebp
00401058   ret

  为什么apple a()这边什么也没有编译呢?原因很简单,因为编译器把apple a()看成是一个extern的函数,返回值为apple。与此相对应的apple b才是函数中真正定义的临时变量,因为在下面不远处有apple的两个函数——apple的构造函数和apple的析构函数哦。

31/3123>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号