- 论坛徽章:
- 1
|
看到有些人对void指针不太清楚,我就试着解释一下,权当抛砖引玉。
大家都知道int *pint是定义了一个指针变量,这个变量里面放的是一个地址,而这个地址里面放的是一个int型的数值。char *pchar是定义了一个指针变量,这个变量里面放的是一个地址,而这个地址里面放的是一个char型的数值。
以此类推……我们也知道在32位计算机上,一般sizeof(pint)是4,也就是说指针变量p的大小是4个字节,每个地址用32位来表示。我们还知道一般sizeof(int)也是4,因为寻址的最小单元是字节,也就是一个int型数据一共占用了4个地址空间。比如定义int i;假设从首地址到末地址分别为:10000,10001,10002,10003(这里为了讨论问题的方便,不考虑bigendian,little endian的问题,有兴趣的可以查找有关资料)。然后int *pint = &因为i占用了4个地址,那么p里面放的是什么呢?p里面放的是变量i的首地址,也就是10000。我们可以用*pint来表示i,当我们这样做时*pint = 10;编译器是怎么解释的呢?编译器的解释是向从10000地址开始的4个字节里面放入整数10。可能你又要问了,编译器又是怎么知道是从10000地址开始的4个字节呢?是的,编译器知道它该这么做,因为pint是一个指针而且它的内容10000,还有p是一个指向int型变量的指针,还因为sizeof(int)是4,所以它可以确保做上面的事情。
好了,罗里罗嗦的说了关于int类型指针这么多,对别的类型指针也是一样。
现在该说说void指针了。void *pvoid;这样定义后,我们必须明确的知道,p也是一个指针,sizeof(pvoid)或sizeof(void *)也是4。给它赋值后,它的内容也是一个地址。比如我们把上面pint赋值给pvoid, pvoid = (void *)pint;现在pvoid和pint的内容完全一样,也是10000。可当你这样使用时,*pvoid = 1;编译器就会报错了。问题就在于pvoid是无类型的指针,也就是它不指向任何类型,你间接引用时,编译器从10000地址开始,要到哪个地址才能结束呢?编译器不知道这些事情,所以它会报错。当我们明确知道pvoid指向的是什么类型,就可以用强制类型转换把pvoid转换为那个类型的指针,例如 *(int *)pvoid = 1;这样就可以了,此时i的值为1。
现在你应该清楚void指针的概念了吧。任何类型的指针都可以赋值给void指针,你也可以把void指针转换成任何类型(当然,你把它转换成并不是它实际指向的类型,结果不可预测。比如你把int型指针赋予void指针,然后把void指针强制转换成doube型指针,并间接引用它,这样的结果不可预测)所以使用时应该把void指针转换成它实际指向的类型。使用void指针增加了程序的灵活性,
但一定要谨慎使用。
这是我刚刚写的,由于是上班,也没有很好的考虑,如果有错误,欢迎指正!下面附带一些测试代码,环境aix5l,gcc3.3
- #include <stdio.h>;
- int main()
- {
- int *pint;
- int i = 10;
- pint = &
- void *pvoid;
- pvoid = (void *)pint;
- printf("sizeof(void *) = %d\n",sizeof(void*));
- printf("pint = %p,pvoid = %p\n",pint,pvoid);
- printf("(int*)i = %d\n",*pint);
- printf("(void*)i = %d\n",*(int *)pvoid);
- printf("(void*)i = %d\n",*pvoid);//不能通过编译
- *(int *)pvoid = 1;
- printf("%d\n",i);
- *(long *)pvoid = 1;//可以编译通过,结果也正确
- printf("%d\n",i);
- *(short *)pvoid = 1;//可以编译通过,结果不正确
- printf("%d\n",i);
- return 0;
- }
复制代码 |
|