指针强制转换
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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 = '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的转换,