指针类型的强制转换
Three q
Q1
指针的强制类型转换,必须显式,指向空间的强制类型转换,本质上就是普通变量的强制类型转换。
指针本身强制类型转换,改变的是对其指向空间的引用方式(空间大小和存储结构)
int a = 10;
int *pa = &a;
float *pb = NULL;
pb = (float *)pa; // 或者 pb = (float *)&a;
当 指针pa存放的地址强制转换成float之后, 赋值给pb。pb里面的地址值与pa里面的地址值是一样的,但是pa存放的是int,而pb存放的是float型,虽然他们指向同一个空间a,但是不同的是,当使用pb取使用空间变量a的时候,会以float型的空间大小和数据存储结构来使用a的值。
Q2
float a = 13.5;
double *pa = (double)&a;
//只是读取空间内容的话,不会引起严重错误
double b = *pa;
//如果是写的话,很有可能会引起严重错误
*pa = 345.45;
a的空间只有四个字节,但是pa以double的形式指向了空间a。通过*pa取读取a的空间值13.5时,除了会读取空间a的四个字节,还会读取空间a后面紧跟的4个字节。如果是写入新数据的话,除了前面4个字节会被写之外,后面紧跟的其他空间的四个字节也会被修改,这会引起严重的错误。所以对于指针变量做强制转换时,多数情况只会讲引用空间缩小,而不会将空间扩大。
Q3
int a = 125;
float *pa =NULL;
float b;
pa = (float *)&a;
float b = *pa;
//打印结果是乱码
printf("%f\n",b);
a和b的空间大小虽然都是个字节,a里面的125是按照整型存储的,但是通过*pa在读取a内容的时候,是按照float进行读取的,结果显然不对。
summary of three Q
对于指针本身的强制类型转换,修改的是对指向空间的引用方式 ,这个过程必须小心,防止引用到别的空间,导致内存越位操作,或者数据访问导致乱码。
指针变量的空间
1.同一种编译器环境下,一个指针变量所占用的内存空间是固定的。比如,在16位编译器下,任何一个指针变量都只占用2个字节,并不会随所指向变量的类型而改变。
数据类型 | 16位编译器 | 32位编译器 | 64位编译器 |
---|---|---|---|
char | 1 | 1 | 1 |
void * | 2 | 4 | 8 |
2. 既然每个指针变量所占用的内存空间是一样的,而且存储的都是地址,为何指针变量还要分类型?而且只能指向一种类型的变量?比如指向int类型的指针、指向char类型的指针。
int i = 2;
char c = 1;
char *p = &c;
printf("%d", *p);
这里输出的结果是1,如果把第三行代码改成 int *p = &c;
输出结果是513
原因:根据变量的定义顺序,这些变量在内存中大致分布如下
变量 | 地址 | 存储的内容 |
---|---|---|
p | ffc1/ffc2 | ffc3 |
c | ffc3 | 0000 0001 |
i | ffc4/ffc5 | ffc4:0000 0010 ffc5:0000 0000 |
其中,指针变量p和int类型变量i各占2个字节,char类型的c占一个字节,p指向c,因此p值就是c的地址
最初的时候,我们用char *p
指向变量c。当利用 *p 来获取变量c的值时,由于指针p知道变量c是char类型的,所以会从ffc3这个地址开始读取1个字节的数据:0000 0001,转为10进制就是1
后来,我们用int *p
指向变量c。当利用 *p 获取变量c的值时,由于指针p认为变量c是int类型的,所以会从ffc3这个地址开始读取2个字节的数据:0000 0010 0000 0001,转为10进制就是513
地址的强制转换
Q1
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
设p的值为0x100000, 如下表达式的值分布为多少
p + 0x1 = 0x_?
(unsigned long) p + 0x1 = 0x_?
(unsigned int*)p + 0x1 = 0x_?
指针变量与一个整数相加减并不是用指针变量里的地址直接加减这个整数。这个整数的单位不是byte 而是元素的个数。
p + 0x1 的值为0x100000+sizof(Test)*0x1。至于此结构体的大小为20byte,所以p +0x1 的值为:0x100014。
(unsigned long)p + 0x1 的值呢?这里涉及到强制转换,将指针变量p 保存的值强制转换成无符号的长整型数。任何数值一旦被强制转换,其类型就改变了。所以这个表达式其实就是一个无符号的长整型数加上另一个整数。所以其值为0x100001。
(unsigned int)p + 0x1 的值呢?这里的 p 被强制转换成一个指向无符号整型的指针。所以其值为:0x100000+sizof(unsigned int)0x1,等于0x100004。
Q2
int main()
{
int a[4]={1,2,3,4};
int *ptr1 = (int *)(&a+1);
int *ptr2 = (int *)((int)a+1);
printf("%x,%x",ptr1[-1],*ptr2);
return 0;
}
ptr1:将&a+1 的值强制转换成int类型,赋值给int 类型的变量ptr,ptr1 肯定指到数组a 的下一个int 类型数据了。ptr1[-1]被解析成*(ptr1-1),即ptr1 往后退4 个byte。所以其值为0x4。
ptr1:将&a+1 的值强制转换成int类型,赋值给int 类型的变量ptr,ptr1 肯定指到数组a 的下一个int 类型数据了。ptr1[-1]被解析成*(ptr1-1),即ptr1 往后退4 个byte。所以其值为0x4。
ptr2:按照上面的讲解,(int)a+1 的值是元素a[0]的第二个字节的地址。然后把这个地址强制转换成int类型的值赋给ptr2,也就是说ptr2 的值应该为元素a[0]的第二个字节开始的连续4 个byte 的内容。