之前一直对指针缺乏认识,因此在使用的过程中也仅仅限制于利用指针来索引变量或者类的实体。然而当我读到Stanley B.Lippman写的Inside The C++ Object Model的时候,对指针的认识豁然开朗。仿佛在写程序定义变量或者类的实体的时候,其内存结构能够立即展现在面前,并且可以通过指针读取任意部分的数据块。
我们都有学过判断计算机大小端的程序样例,在最初读到这个程序的时候感到有些懵,其实当时根本没有理解其指针变换的原理,以至于很快就将其忘掉了。程序大体是这样的:
#include<iostream>
using namespace std;
int main(int argc, char * argv) {
short int a = 0x3132;
char *b = (char *)&a;
cout<<b[0]<<" "<<b[1]<<endl;
}
对于小端机器,那么输出顺序是2 1,,而大端则是1 2,这是一个非常简单的指针类型转换的例子。
对于指针,最关键的是要理解两点,一点是值,一点是类型。值表示了指针的指向数据在内存上的起始位置,而类型则表示了数据块的大小。第二点最直接的理解方式是,当我们看到一个指针p的时候,我们就自然而然地会去想p+1会是什么地方,那么这个时候我们就要根据指针类型来判断。
如
int a = 5;
int *p = &a;
cout<<p+1<<endl;
倘若p的值是1000,int型占4个自己空间,那么输出结果应该是1004,即下一个整型数的位置。p+1跳过的距离,实际上就是p的类型所占用的内存空间的字节数。因此我们就可以灵活地利用指针来读取内存中的数据,而不被数据本身的类型所限制。正如上面的判断大小端的程序,short int占用两个字节,分别存储了0x31和0x32,如果我们想要单独读取0x31那么就需要获得一个这样的指针,首先p的类型必须是1个字节,这样可以一次性刚好读取0x31,然后p必须可以通过移动的方式指向0x31,因此将a的地址强制转换成char *型即可。对于基本数据类型,我们都可以通过相互强制转换的方式来控制读取的数据块的大小,从而达到特殊的目的。
int main(int argc, char * argv) {
struct s {
int a;
int *b;
};
int v = 8;
s m;
m.b = &v;
m.a = 5;
cout<<sizeof(m)<<endl; // total 16, a 4 ,aligment 4, b 8
int *p = (int *)&m;
cout<<m.a<<endl; // get a value
cout<<*p<<endl; //use p get a value, p point to m and a int type.
cout<<&m.b<<endl;//get address of m.b
cout<<p+2<<endl; //get address of m.b using p, p+1 is aligment not used.
cout<<*(m.b)<<endl;//get value m.b pointed.
cout<<*(int *)*(long int *)(p+2)<<endl;
//get valuse m.b pointed using p. Here v can see p+2 pointed to the start of b.
//For b is 8byte, we need to convert p+2 to a 8byte type pointer such as long int *
// now (long int *)(p+2) is a pointer which pointed to the context m.b, so *(long int *)(p+2) can get the context of b which is same with m.b
// but when we get the address using *(long int *)(p+2), we didn't it's type ,so we need to convert the type to int *, when we can get the right value
}
输出结果:
16
5
5
0x7fffd908dec8
0x7fffd908dec8
8
8
可以看到我们完全可以通过指针和指针类型的转换来读取结构体内的数据,这就需要对结构体的内存存储方式有充分的了解,包括内存对齐,指针类型及各个类型所占用内存的大小。另外,对于C++中类的实例中的各个成员以及虚函数表等操作都需要与此类似的操作,这就需要进一步研读C++对象模型。
参考教材:
Inside The C++ Object Model, Stanley B.Lippman
《深度探索C++对象模型》 侯捷 译