C语言学习的重点之一就是指针。通过反汇编,能够直接透视指针的本质
指针是什么?指针存储了内存的地址,是一个存储空间,其中存放内存中的地址信息,指针是有类型的,如int*、float*
因此,我们猜想指针变量应该存储有这两方面的信息,地址和指针类型,如:
struct pointer{
long address; //地址
int type; //指针的类型
};
先做一个简单的实验,sizeof(int *)、sizeof(float*)实验结果都是4,不是8,这4字节包含的是什么内容呢——32位地址,也就是说,指针变量并没有存储类型信息。那为什么还有指针类型、强制转换……
并且如果不转换,不同类型的指针无法赋值(如int * 赋值给float * 就是错误的)
#include "stdafx.h"
int gi;
int *pi;
int _tmain(int argc, _TCHAR* argv[])
{
pi = &gi;
*pi = 12;
return 0;
}
pi = &gi;
0041138E mov dword ptr ds:[00417140h],417144h
gi的地址是0x417144,指针变量pi自身的地址是0x00417140
mov指令将gi地址,放入到指针变量pi中,显然,指针变量确实只有地址信息
难道真的没有类型信息吗?
指针是用来访问内存的,访问内存,只要地址就可以了吗?显然不是的,还需要知道访问多少字节——类型信息
mov dword ptr ds:[00417140h], 417144h
mov中的dword ptr(double word),说明要赋值4个字节(0x00417144,而非3个字节),这就是类型信息,指针变量只存储了地址信息,而类型信息,即访存大小信息,存放在mov指令的dword中。到此为止,我们能够发现指针的类型决定了赋值/读取的时候写/读了多少字节。
读写多少字节的信息不是存放在指针变量当中,而是放到了与该地址相关的赋值指令当中,mov指令中的dword指明了这个信息。
C语言之所以要包装出指针的概念,是在汇编地址的内涵上增加另一层含义,即读/写多少字节。不同类型指针,访问字节数不同,int * 访问4个字节,short * 访问两个字节。
这样方便我们操控地址,否则的话,每次访问它还要附加说明访问的字节数。
这时我们也能理解,指针加1减去1都不是加减1字节而是加减相应长度的字节数。
*pi = 12;
00411398 mov eax,dword ptr ds:[00417140h]
0041139D mov dword ptr [eax],0Ch
很明显,在int型的指针pi赋值为12 的时候,由于12也是默认为int型的,很easy
首先将pi指针的地址 保存在eax当中 累加器 然后将0Ch的数值付给dword ptr 【eax】就可以了
疑惑,为什么不是一句mov代码就完成了呢?
明白了第一次是为了获得指针地址当中存储的内容(是目的地址)第二次才是将0Ch写入目的地址对应的内存单元当中去。
立即数不能当中目的地址的,本来就是不能。
00417140h 是pi的地址,dword ptr ds:[00417140h] 是pi地址当中的内容 并不能当做操作数的,因为并不是我们的目的地址。
// 1.5.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
short gi;
short *pi;
int _tmain(int argc, _TCHAR* argv[])
{
pi = &gi;
*pi = 12;
return 0;
}
*pi = 12;
00411398 mov eax,0Ch
0041139D mov ecx,dword ptr ds:[00417140h]