c语言中void *的使用

本文深入探讨了指针变量的存储原理,解释了指针与void*之间的转换规则,包括int*、double*、char*和struct*转void*的直接转换,以及void*转其他类型指针时的强制类型转换。同时,分析了void*作为泛型指针在函数形参和返回值中的应用优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、前言

指针变量占4个字节,不受所指向的变量类型影响,int型变量占4个字节,double占8个字节。比如int*p ,dounble *q ,p和q(类型都是*,也就是指针)指针变量都是占4个字节,但是,其分别指向的变量所占的字节数是不同的。

1)指针变量存储的是所指向变量的地址,这个地址值也就是一个整型常量。

2)int*转void*,可以不用强制类型转换(具体转换成抽象,模糊掉类型//void * 可以理解为各种指针的或)

例1:int *p; void*q;  q =p;

例2:void *memset(void *s, int c, unsigned long n);

char str[5];
memset(str,0,sizeof(str)); //char*转void* 没有进行强制类型转换。

3)void*,转int*,得用强制类型转(抽象转具体//当然要表明是要转到哪一种指针类型)

int *p; void*q;  p =(int*)q;

2、类型转换

1)正常情形的转换(指针转指针)

int* 、 double* 、 char* 和 struct *  转void*:直接转,不需要强制类型转(因为void*的是任意指针,范围广)

void *   转 int*  、double*  、char*  或struct *  :需要强制类型转,范围大转范围小(例:void *p =NULL,int* a = (int*)p;)

2)int 和void*的转换

例1:指针转int ----->指针变量中的值是个 十六进制整型

int a =1;

int *p = &a;

printf("%x\n",(int)p);//打印出p是十六位进制数

例2:int 转void *

int a= 0x1234;
void *p;
p = (void*)a;//注意:此时p指向0x1234这个内存地址,但是内存地址并不存在。

注意:此时p指向0x1234这个内存地址,但是内存地址并不存在。

void *func()
{
    return (void*)0;//相当于return NULL;
}

例3:void* 转int

int a= 0x1234;
void *p;
p = (void*)a;//注意:此时p指向0x1234这个内存地址,但是内存地址并不存在。


int b = (int)p;//void* 转int

 注意:用void*与int互转,是因为二者的字节数相等的,不会出现丢位的情况,void*跟double就不行了,因为double所占字节数更多。

3、void* 是一个泛型指针,一般作为函数形参和函数返回值。

3.1、作为函数形参

使用void* 时要进行强制类型转换:

myFunc(void *temp)//函数定义

{

     int  result = *((int*)temp);//转换回来

}

int value =2;

myFunc((void*)&value);//函数调用时

3.2、作为函数返回值

(void*)(*start_rtn)(void*)

{

     return (void*)0;

}

(void*)0等价于NULL。//NULL的ascii码值为0.

4、形参为void*的优势:

1)void*表示,此处可以是任意的指针类型;(以后就这么理解)

2)普通类型的指针不需强转,可以直接赋值给void*

void* 类型的指针赋值给普通类型指针需要强制类型转换。

普通类型的指针,虽然本身所占的字节数都相同,但是跳跃度不同,

比如,int* p  ; p++;

和 double *q; q++;二者的跳跃度不同。

我们以pthread_create()函数为例分析如下:

#include <pthread.h>
int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,(void*)(*start_rtn)(void*),void *arg);

如上所示,pthread_create函数中使用了函数指针start_rtn,以及start_rtn的形参arg;

作为pthread_create来说,只是单纯的调用函数start_rtn,并不需要知道start_rtn函数的形参类型是什么。只需要写一种函数形式就行。

int value =2;

pthread_create(&pid,NULL,myFunc,(void*)&value);

int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,(void*)(*start_rtn)(void*),void *arg);

{

    start_rtn(arg);

}

参数为指针时,当无须传递参数时,形参置NULL。

ps:系统仅提供了pthread_create函数, 函数 (void*)(*start_rtn)(void*)和参数void *arg都是程序员自定义的,也就是说,函数参数void*和参数void *arg 中的数据类型void* 是程序员自己确定,保持一致即可。对于系统来说,不确定程序员会传递一个什么类型的值,所以,就使用void*

另外还有另一种情况,例如文章中定义了memcpy的函数原型和函数实现

void *memcpy(void *memTo, const void *memFrom, size_t size)
{
  if((memTo == NULL) || (memFrom == NULL)) 
         return NULL;
  char *tempFrom = (char *)memFrom;             
  char *tempTo = (char *)memTo;                      
  while(size -- > 0)                
         *tempTo++ = *tempFrom++ ;  
  return memTo;
}

函数参数也为void * ,在函数实现中,我们都转换成char* ,并通过解引用,单个字节,单个字节的取数。

这种情况下,函数内部实现是通过char* ,但是参数类型为void*,使用该函数的时候,无论是什么指针类型,都可以直接传参即可,而不用进行强制类型转换,当然,转一下也是可以的比如

char ch[128];

struct st{

int mm;

double bb;

}  nn;

nn.mm = 2;

nn.bb = 2.3;

memcpy(ch,(char*)&nn,sizeof(struct st));  //(char*)&nn 是不是用char* 转应该都行。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值