0x01:引入指针地址强转概念

从下面这个例子引入强制转换的概念:

struct test{
	char string[2];  //2
	int *point;   //4
	int nu[2];    //8
	short data[3];  //6
}*p;

如果p 的值为0x100000。如下表表达式的值分别为多少?

p + 0x01 = 
(unsigned long)p + 0x01 = 
(unsigned int*)p + 0x01 =

0x02:分析实例

主要的原理还是在前面一篇文章有说到,表达式“a+1”与“&a+1”之间的区别,同理,指针变量与一个整数相加减并不是用指针变量里的地址直接加减这个整数。这个整数的单位不是byte 而是元素的个数。
Q1: p + 0x1 的值为0x100000+sizof(test)0x1。至于此结构体的大小为20byte,所以p +0x1 的值为:0x100014;
Q2: (unsigned long)p + 0x1 的值呢?这里涉及到强制转换,将指针变量p 保存的值强制转换成无符号的长整型数。任何数值一旦被强制转换,其类型就改变了。所以这个表达式其实就是一个无符号的长整型数加上另一个整数。所以其值为:0x100001;
Q3:(unsigned int
)p + 0x1 的值呢?这里的p 被强制转换成一个指向无符号整型的指针。所以其值为:0x100000+sizof(unsigned int)*0x1,等于0x100004;

0x03:实例解析

实例代码:

//point.c
#include <stdio.h>
int main()
{
	int a[4] = {1,2,3,4};

	int *p1 = (int *)(&a+1);
	int *p2 = (int *)((int)a+1);

	printf("The a address is %p\n",&a);
	printf("The a+1 address is %p\n",&(a[1]));
	printf("The (int)a address is %p\n",(int)a);
	printf("The (int)a+1 address is %p\n",(int)a+1);
	printf("%x %p\n",p1[-1],p2);

	return 0;
}

Linux 环境下使用GCC进行编译:

curtis@curtis-virtual-machine:/mnt/hgfs/share/write_code/c_test$ gcc point.c 
point.c: In function ‘main’:
point.c:57:20: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
  int *p2 = (int *)((int)a+1);
                    ^
point.c:57:12: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
  int *p2 = (int *)((int)a+1);
            ^
point.c:61:38: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
  printf("The (int)a address is %p\n",(int)a);
                                      ^
point.c:61:2: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’ [-Wformat=]
  printf("The (int)a address is %p\n",(int)a);
  ^
point.c:62:40: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
  printf("The (int)a+1 address is %p\n",(int)a+1);
                                        ^
point.c:62:2: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’ [-Wformat=]
  printf("The (int)a+1 address is %p\n",(int)a+1);

输出结果:

curtis@curtis-virtual-machine:/mnt/hgfs/share/write_code/c_test$ ./a.out 
The a address is 0x7ffe7e4ddd20
The a+1 address is 0x7ffe7e4ddd24
The (int)a address is 0x7e4ddd20
The (int)a+1 address is 0x7e4ddd21
4 0x7e4ddd21

0x04:结果分析
p1:将&a+1 的值强制转换成int类型,赋值给int 类型的变量p,p1 肯定指到数组a 的下一个int 类型数据了。p1[-1]被解析成*(p1-1),即p1 往后退4 个byte。所以其值为0x4。
p2:按照上面的讲解,(int)a+1 的值是元素a[0]的第二个字节的地址。然后把这个地址强制转换成int类型的值赋给p2,也就是说p2 的值应该为元素a[0]的第二个字节开始的连续4个byte 的内容。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐