指针强制转换

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1、指针类型转换请使用static_cast、dynamic_cast等操作

2、指针变量(不管那种指针),大小都是四个字节,内容就是指向的对象的首地址。不同类型指针不同点就是对首地址之后的那块内存会做不同解释。

建议你看看《Inside C++ Object Model》里面关于指针的内容,里面有清晰的说明

int * pi = new int;

pi 指向了一块内存的首地址,这块内存应该有sizeof(int)个字节,

由于pi是int *类型,所以通过pi进行的操作,编译器都认为pi的内容是一个有sizeof(int)个字节的int 型变量的首地址,所以*pi = 4,遇到这样的操作,编译器产生的代码就是把4这个数付到pi所指的四个字节里。

char * pc = (char *)pc; //建议这样写char * pc = static_cast (pc);

*pc = '4 ';

由于pc是char *类型,所以通过pc进行的操作,编译器都认为pc的内容是一个有sizeof(char)个字节的char型变量的首地址,所以*pc = '4 ',遇到这样的操作,编译器产生的代码就是把4这个字符付到pc所指的第一个字节里。虽然,pc实际指向的是int型的变量,有4个字节。

改变指针的类型,解引用操作的时候会影响到所指向的地址内容(类型所占的字节数可能不同,还有高位是符号位或是数据位)解析,不会发生数据丢失

未必!设想下面三个类:

class A

{

public:

int m_nA;

A():m_nA(1){}

public:

A* GetA(){ return this; }

};

class B

{

public:

int m_nB;

B():m_nB(2){}

};

class C : public A, public B

{

public:

int m_nC;

C():m_nC(3){}

};

int main()

{

C *c = new C;

此处调试察看c指向的内存空间,假设以c的指向为基点,其后的地址以偏移记

那么整个c所指向的对象在内存中的排列如下:

(0)四个字节的m_nA (4)四个字节的m_nB (8)四个字节的m_nC (12)......

这里只关心最前面的12个字节,再看:

A *a = c-> GetA();

此处察看a,和c一样,它也指向上面的(0)处。这没有问题,通过它来访问

m_nA会得到1,完全正确。再看:

B *b = (B*)a;

此处得到的b和a的指向完全一样,通过它来访问m_nB得到的值是不正确的。不

过,如果通过它来访问B的非虚的成员函数,可以得到正确的结果。

这里的强制转换仅仅是改变了指针的类型。看下面最关键的:

b = (C*)a;

b居然指向了(4)处,这句代码居然得到了正确的地址!也就是说,这里的强制

转换不仅改变了指针的类型,同时也改变了指针的值。为什么?

return 1;

}

把指向派生类的指针,转换为不是第一个基类的指针时,必须要对其地址做出改变

这样才可以使派生类指向该基类,这点inside the c++ object model书上讲了的

关于这里:

B *b = (B*)a;

此处得到的b和a的指向完全一样,通过它来访问m_nB得到的值是不正确的。不过,如果通过它来访问B的非虚的成员函数,可以得到正确的结果。

这里的强制转换仅仅是改变了指针的类型

由于a是个指向类型A的指针,这种转换就和派生类毫无关系,仅是将一个类的指针

转换为指向另一个类(相当于这两个类没有任何联系,实际上A,B之间是毫无联系的)

并不像这样

b = (C*)a;,a转换为C的指针后,b和c有了基类和派生类的关系

问题就是关于*b的,b是一个指向char型的指针,将&a解释成(char*)的类型,从而*b也就是a的最高位的那个字节,所以我感觉*b结果应该是0x000000ff,那里错了?

char * b = (char *)&a;

是将a的地址转换成char *类型,实际上就是b存放a这个变量的地址。也就是说b指向了a所以对b进行解引用得到的就是a了

因为你用的是x86 CPU,将整形的高字节放在地地址处,也就字节顺序从高到低,地址从低到高顺序0xff fffff7

1)little-endian的话,*b指向的是最低的那个字节也就是f7,这个上面已经说过了;

2)我想补充的是,即使指向的是高位字节,你的输出也不是0x000000ff,而是全f,符号位扩展的原因char相当有符号的整数,所以打印fffffff7.

如果是:

unsigned char * b = (unsigned char *)&a;

那么也打印000000f7

其实b指向的就是最后一个字节f7,而char是有符号的,高位用ff补齐,而unsigned是无符号的,就直接打印一个字节的内容,高字节就用0补齐

#include

int main(void)

{

unsigned int a = 0xfffffff7;

unsigned char i = (unsigned char)a;

char * b = (char *)&a;

unsigned char * c = (char *)&a;

int d = *b;

int e = *c;

printf("%08x\n%08x %08x %d %d\n", i, *b, *c, d,e);

return 0;

}

打印结果:

000000f7

fffffff7 000000f7 -9 247

我们用2进制来写这些数字,并且参考6楼,增加一个unsigned char的指针或者数字。

为了书写方便,我这里都直接取数了,不进行指针操作。

unsigned int a = 1111 1111 1111 1111 1111 1111 1111 0111

因为a是无符号型,所以最高位的1是表示2的63次方。

unsigned char i = 1111 0111

char b = 1111 0111

unsigned char c = 1111 0111

注意b的最高位的1,并不是表示2的7次方,而是表示b是负数。

所以查看他们的值,会发现,b是-9.利用补码加1,可以算出确实是-9,c和i都是247,也可以算出来。所以int到char 的强制转换,不管是不是无符号型,肯定是截取了低16位。

什么呢?因为c/c++标准规定char类型可以是signed char,也可以是unsigned char,这就是实现相关。编译器可以自行选择其中一种,一般情况下编译器会

提供选项让用户选择。你所得到的结果,是因为你当前编译环境设定char是signed char而得到的。

由于*b是signed char,在作为参数传入printf之前,*b被自动提升为int,这是一个到signed int的转换,

相关文档
最新文档