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

来源:互联网 发布:万能数据恢复软件下载 编辑:程序博客网 时间:2024/05/01 13:29

          工作闲暇的时候,同事跑来问我做一道关于C++的笔试题目,题目是这样的:

     int szNum[5] = { 1, 2, 3, 4, 5 };

             int *ptrA = (int*)(&szNum+1);

             int *ptrB = (int*)((int)szNum + 1);

             std::cout << ptrA[-1] << *ptrB << std::endl;

问打印结果是什么?

   拿到题当然不能上机拿结果了:),不然就没有思考的乐趣了,首先就得自己分析一下了,对于ptrA,看到等式的右边就不难发现是考察的指针算术的概念,就是说对指针做算术不是简单的加一或者减一,而是要看其指针类型来做决定,这里szNum是一个指向整型数组第一个元素的指针,则其做取地址的操作的时候得到的是指向含有5个元素的整型数组的数组指针,也就是说其+1的时候数组指针应该会向后移动1个含有5个int元素的数组单位,也就是就是指向移动5个int单位之后的那个地方,而要打印的结果是ptrA[-1],表示是要回退一个int单位,所以结果应该是指向5的,应此ptrA[-1]打印的结果就应当是5,后面一个ptrB指向的答应结果又是什么呢,我们接下来继续分析,首先把数组的首地址转换成int类型,而后再加1,这里的加1就和上面的那个不一样了,这里考察的是Address Arithmetic(地址算术),这次的对象变成了一个首地址值,因此加一的话,应该是意味着加上一个字节,也就是说,这个首地址+1个字节的offset(偏移量),该地址里面存的结果又该是多少呢?这里我想到了一个叫做Big Endian&Little Endian的问题,也就是说

Big endian machine: It thinks the first byte it reads is the biggest.

大尾端机器:认为其读的第一个字节为最大的那位上的数。
Little endian machine: It thinks the first byte it reads is the littlest

小尾端机器:认为其读的第一个字节为最小的那位上的数。

而X86系列的机器据我所知都是Little endian的机器,因此在其存储的过程中就应当是如下的图景:(为了说明问题,地址乃自己构造的,内容是数组首地址指向的元素值,以及第二个元素值)

0X0001 : 01

0X0002 : 00

0X0003 : 00

0X0004 : 00

0X0005 : 02

0X0006 : 00

0X0007 :  00

0X0008 :  00

(int)szNum + 1 因此这个结果就为0X0002了,而其指向的结果是一个int型的元素,大小为四个字节,因此按照little endian机器的读法就是02 00 00 00了,结果的十六进制数就是0X2000000,转换为十进制数就为33554432,因此整个题目的打印结果是533554432。

OK,现在可以在电脑上去验证一下了:

int szNum[5] = { 1, 2, 3, 4, 5 };
004124BE  mov         dword ptr [ebp-18h],1
004124C5  mov         dword ptr [ebp-14h],2
004124CC  mov         dword ptr [ebp-10h],3
004124D3  mov         dword ptr [ebp-0Ch],4
004124DA  mov         dword ptr [ebp-8],5

首先是这个数组初始化后5个元素所存储的位置,可以发现这里int型占四个字节,

int *ptrA = (int*)(&szNum+1);
004124E1  lea         eax,[ebp-4] //加载移动后地址里的数据到EAX(好奇的人会问移动之前是那个地方呢?其实算一算就知道了(不用算也知道哈哈,肯定是首地址的位置,为了证实一下算一算熟悉过程),移动以后是ebp-4,移动了5个int元素的空间也就是20个字节,20 == 0X14h,那么移动前就是ebp-4h-14h == ebp - 18h)

004124E4  mov         dword ptr [ebp-24h] //把指向int元素的指针地址赋给ptrA

 int *ptrB = (int*)((int)szNum + 1);
004124E7  lea         eax,[ebp-17h] //地址算术原来是ebp-18h移动一个字节后变成ebp-17h
004124EA  mov         dword ptr [ebp-30h],eax  // 赋值

好了分析完毕了,我想说的是在c++编程过程中还是了解点底层好,特别是汇编,这样很容易分析出结果,对于指针的一些复杂操作通过对底层的了解,看看汇编出来的结果就很容易理解了,有空的时候我会分析一下 ++ptr和ptr++以及 A+=B 是否真的是 A = A + B的问题(我记得上学的时候就有人讲过不过不幸的是误导居多),以及c++程序的汇编结构问题,这些问题同样是通过汇编看底层很容易理解的。

 

   

原创粉丝点击