万能指针void*学习

 

1)可以用任何类型的指针对 void 指针进行赋值

  由于void 指针没有特定的类型,因此可以指向任何类型的数据。因此他可以指向任何类型的数据。也就是说,任何类型的指针都可以直接赋值给 void 指针,而无需进行其他相关的强制类型转换。

  例如:

  double d = 1.54;

  void * p = & d;

 

2)void 指针不可以直接赋值给其它类型的指针

  因为 “空类型” 可以包容 “有类型”,而 “ 有类型” 则不能包容 “空类型”。

  由此可见,要将 void 指针赋值给其他类型的指针,必须进行强制类型转换。如:

1 void * p1;
2 int * p2;
3 . . .
4 p2 = (int *)p1;

 

 

3)避免对 void 指针进行算术操作

  ANSI C 标准规定,进行算法操作的指针必须确定知道其指向数据类型大小,也就是说必须知道内存目的地址的确切值。

1 char a[20]="qwertyuiopasdfghjkl";
2 int *p=(int *)a;
3 p++;
4 printf("%s", p);  // tyuiopasdfghjkl

  p++;一步前进了sizeof(int)=4 个字节,而类型为char,sizeof(char)=1

  对于 void 指针,编译器并不知道所指对象的大小,所以对 void 指针进行算术操作都是不合法的,如下面的示例代码所示:

1 void * p;
2 p++;    // ANSI:错误
3 p+= 1; // ANSI:错误

  

  但值得注意的是,GNU 则不这么认为,它指定“void*”的算法操作与“char*”一致。因此下列语句在 GNU 编译器中都是正确的:

1 void * p;
2 p++;      // GUN:正确
3 p+=1;      // GUN:正确

  下面代码演示了在 GCC中 执行对 void 指针的自增操作:

1 #include <stdio.h>
2 int main(void)
3 {
4     void * p="ILoveC";
5     p++;
6     printf("%s\n", p);  //输出:LoveC
7 }

  由此可见,GNU 和 ANSI 还存在着一些区别,相比之下,GNU 较 ANSI 更“开放”,提供了对更多语法的支持。但是在真实的设计环境中,还是应该尽可能符合 ANSI 标准,尽量避免对 void 指针进行算术操作。

 

4)应用:内存操作函数

  根据 1)中的内容,void 指针可以指向任意类型的数据,同时任何类型的指针都可以直接赋值给 void 指针,而无需进行其他相关的强制类型转换。因此,在编程中,如果函数的参数可以是任意类型指针,那么应该使用 void 指针作为函数的形参,这样函数就可以接受任意数据类型的指针作为参数。

 1 void *memset(void *buffer, int b, size_t size)
 2 {
 3     assert(buffer!=NULL);
 4     char* retAddr = (char*)buffer;
 5     while (size-- > 0)
 6     {
 7         *(retAddr++) = (char)b;
 8     }
 9     return retAddr;
10 }
11 
12 
13 void *memcpy (void *dst,  const void *src,  size_t size)
14 {
15     assert((dst!=NULL) && (src!=NULL));
16     char *temp_dest = (char *)dst;
17     char *temp_src = (char *)src;
18     char* retAddr = temp_dest;
19     size_t i = 0;
20     /* 解决数据区重叠问题*/
21     if ((retAddr>temp_src) && (retAddr<(temp_src+size)))
22     {
23         for (i=size-1; i>=0; i--)
24         {
25             *(temp_dest++) = *(temp_src++);
26         }
27     }
28     else
29     {
30         for (i=0; i<size; i++)
31         {
32             *(temp_dest++) = *(temp_src++);
33         }
34     }
35     *(retAddr+size)='\0';
36     return retAddr;
37 }

 

posted @ 2020-02-11 13:07  egu0o  阅读(605)  评论(1编辑  收藏  举报