0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何理解C++中的void?

jf_78858299 来源:小余的自习室 作者:小余的自习室 2023-03-30 15:01 次阅读

1.定义

首先void*中的void代表一个任意的数据类型,"星号"代表一个指针,所以其就是一个任意数据类型的指针。

对于指定数据类型的指针如int* ,double*等,他们的sizeof都是4个字节,因为都是一个指针,只是指针指向的数据类型不一致。

C语言是一个强类型的语言, 那么他们之间有什么区别呢 ?前面一篇文章我们说过, 指针+1和-1是和指向数据类型有关的

假设指针值为0x00000001,指针类型为int类型,整数为n,则计算出来的结果为0x00000001+ n乘以4,这里的4是因为指针类型为int,如果是double,则为0x00000001+ n乘以8. 所以我们使用double类型指针+1,地址移动了8位,而用int指针+1,地址移动了4位,就是这个道理。

这说起来其实和数据内存对齐有关。你可以把这里的4和8理解为跳跃力。

那对于void*呢? 其实就是一个未指定跳跃力的指针

那void*的跳跃力又什么时候指定?在需要使用的时候指定就可以了,好处: 可以实现泛型编程,节省代码

2.void*使用场景

2.1:当函数传参时不确定数据类型时或者支持多种数据类型传递时。

代码如下:

void say(int type,void* pArgs) {
    switch (type) 
    {
        case 0:
        {
            double* d = (double*)pArgs;
            break;
        }   
        case 1:
        {
            int* i = (int*)pArgs;
            break;
        }       
    }
}

该函数使用一个type来表示当前参数void*的类型,内部通过type判断转换的类型。

2.2:函数返回值不需要考虑类型,只关心返回的大小。

如malloc函数:

原型:

void* malloc(size_t size)

代码使用:

int* a = nullptr;
double* b = nullptr;
b = (double*)malloc(sizeof(double));
a = (int*)malloc(sizeof(double));

可以看到malloc返回值类型为void*,其只返回分配内存的大小,不关心分配后的内存你是使用int还是double类型进行划分.

注意:函数外部在接收到void*格式的返回值时,需要强转为自己的数据类型才能使用。

3.void*使用中的注意点:

1.使用赋值运算符“=”时,void*只能作为左值不能作为右值。

void*作为一个未指定数据类型的指针,可以指向任何一个数据类型的指针,但是有数据类型的指针,不能指向一个void* 的指针。

代码如下:

int i = 5;
int* pi = &i;
void* pv = pi;
int* pi1 = pv;//编译错误,void*类型的指针不能初始化为指定类型的指针

这其实是可以理解的:

假设void*指定了一个非int类型的数据,如果此时赋值给int*类型的指针,则会发生严重的bug**。

2.void*类型必须强转为指定类型的数据才能使用。

void 在未指定类型的情况下,是不能直接使用的, 只有在转换为显示类型后才能使用 *

代码如下:

int i = 5;
int* pi = &i;
void* pv = pi;
//cout << *pv << endl;//表达式必须是指向完整对象类型的指针
cout << *(int*)pv << endl;

代码中可以看出在未强转为显示类型前,使用void*会报表达式必须是指向完整对象类型的指针.

说明void*一定要强转后才能使用.

没有强转的void*是没有意义的。

那可能有同学要问了,假设我们并不知道当前void*数据类型,强转错误了会发生什么事。

int i = 5;
int* pi = &i;
void* pv = pi;

cout<<"(int*)pv:" << (int*)pv << endl;
cout<<"(double*)pv:" << (double*)pv << endl;
cout <<"*(int*)pv:" << *(int*)pv << endl;
cout <<"*(double*)pv:" << *(double*)pv << endl;

运行结果:
(int*)pv:0043F724
(double*)pv:0043F724
*(int*)pv:5
*(double*)pv:-9.25596e+61

此时可以看到虽然pv强转为double后,指针指向的地址和强转为int类型指针指向地址是一样的都是0x0043F724。但是取值后就发生了异常,因为double占用的是8个字节,所以取值的是后8位字节,所以取到的是一个错误的值,实际只有4个字节是有效的。

我们在使用void*强转的时候一定要注意这点

3.C++中使用(void*)0表示空指针。

在C语言中空指针定义方式:

#define NULL ((void*)0)

在C++语言中:

#ifndef NULL
    #ifdef __cplusplus
        #define NULL 0
    #else 
        #define NULL ((void*)0)
    #endif
#endif
可以看到在C语言中NULL代表(void*)0,而在C++中NULL代表的是0,使用nullptr来表示(void*)0空指针,
所以在C++中推荐使用新标准的nullptr来初始化一个空指针。

4.当void*作为函数的参数类型或者返回值类型时,说明该函数可以接收或者返回任意类型的指针。

代码如下:

void* _say(void* pArgs) {
    return pArgs;
}
int  main()
{
    int _a = 5;
    float f = 10.8;
    int* _pi = &_a;
    float* pf = &f;

    cout << *(int*)_say(_pi) << endl;
    cout << *(float*)_say(pf) << endl;

}
运行结果:
5
10.8

代码中可以看出参数void* pArgs可以使用任意类型的实参,返回值也可以返回任意类型的指针,但是最终需要转换为具体类型才能使用。

void*在C++中的作用其实就是为了实现泛型编程,和Java中使用Object来表示是一样的,所以又称为通用指针和泛指针,不过 C++中大部分情况下会使用模板编程来实现泛型

上面_say函数代码可以使用下面模板函数代替:

T _say(T t) {
    return t;
}

区别在于: 模板编程不需要将强制转换为具体类型 ,其使用方式如下:

int _a = 5;
float f = 10.8;
int* _pi = &_a;
float* pf = &f;

cout <<*_say(_pi) << endl;
cout << *_say(pf) << endl;

未强转也可以直接得出结果,这是因为模板编程会在编译器帮我们生成具体的函数。

调用了两次_say会分别实现:

float* _say(float* t) {
    return t;
}
int* _say(int* t) {
    return t;
}

所以运行的时候是调用了不同的函数,而使用void*的泛型只调用一个函数。

总结

  • 1.void*是一个过渡型的指针状态,可以代表任意类型的指针,取值的时候需要转换为具体类型才能取值。其是处于数据类型顶端的状态:

    图片

  • 2.void* 使用赋值运算符“=”赋值时,只能将具体类型赋值给void星,不能将void*赋值给具体类型。

  • 3.void*一般作为参数或者返回值来实现泛型编程,但是C++中一般考虑使用模板编程来实现。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据
    +关注

    关注

    8

    文章

    6837

    浏览量

    88754
  • C++
    C++
    +关注

    关注

    21

    文章

    2102

    浏览量

    73457
  • void
    +关注

    关注

    0

    文章

    23

    浏览量

    9851
收藏 人收藏

    评论

    相关推荐

    C++的结构和类

    C++ 仍然是嵌入式开发的少数​​语言,但当项目变得太大而无法有效使用 C 时,开发人员通常会采用 C++。这些开发人员通常从 C 过渡到 C++
    发表于 07-18 17:37 785次阅读

    C语言和C++那些不同的地方

    ++11标准。根据不同的标准,它们的功能也会有所不同,但是越新的版本支持的编译器越少,所以本文在讨论的时候使用的C语言标准是C89,C++标准是C++99.我们来介绍
    的头像 发表于 12-07 14:29 894次阅读
    <b class='flag-5'>C</b>语言和<b class='flag-5'>C++</b><b class='flag-5'>中</b>那些不同的地方

    void(*isr)(void)__irq怎么理解

    void(*isr)(void)__irq怎么理解,求高手指教!
    发表于 08-10 14:12

    C++笔记003:C++从一个小程序开始

    ,暂且这样理解。<<这个左移操作符,我们发现已经“变味”了,在C++里面已经进行功能的改造,跟以前C语言的左移操作符用法不一样了,这就是C++
    发表于 03-05 12:51

    C++笔记004:C++类通俗点说—— C结构体复习

    的程序设计,对象具有属性(状态)和行为,属性保存在成员变量,行为通过成员方法(函数)来实现。成员方法又是什么?其实方法和函数可以理解为一回事。只是在C++
    发表于 03-05 12:53

    如何把C++的源程序改写成C语言

    加一八零二五二六七六九二(微信)方法有两种:第一种是将C++的面向对象特征去掉,先全部理解源代码的逻辑,然后改写;第二种是在C中保留面向对象的部分特征,用结构体实现类的功能。第一种方
    发表于 07-05 14:59

    C/C++程序员实用大全配套代码

    CC++程序员实用大全》配套代码  [涉及平台] VC++ [作者] void [文件大小] 629KB  [更新日期] 2005-10-28
    发表于 02-09 11:18 28次下载

    C语言voidvoid指针深层探索

    1.概述 本文将对void关键字的深刻含义进行解说,并详述voidvoid指针类型的使用方法与技巧。 2.void的含义 void的字面意
    发表于 09-21 11:36 166次下载

    EE-128:C++的DSP:从C++调用汇编类成员函数

    EE-128:C++的DSP:从C++调用汇编类成员函数
    发表于 04-16 17:04 2次下载
    EE-128:<b class='flag-5'>C++</b><b class='flag-5'>中</b>的DSP:从<b class='flag-5'>C++</b>调用汇编类成员函数

    浅析C++this指针的理解以及作用

    01 C++程序到C程序的翻译 想要理解C++语言中的this指针,下面我们做一个举例,我们要先把下面的C++代码转换成
    的头像 发表于 06-27 11:24 2895次阅读
    浅析<b class='flag-5'>C++</b><b class='flag-5'>中</b>this指针的<b class='flag-5'>理解</b>以及作用

    C++如何用虚函数实现多态

    01 — C++虚函数探索 C++是一门面向对象语言,在C++里运行时多态是由虚函数和纯虚函数实现的,现在我们看下在C++如何用虚函数实现
    的头像 发表于 09-29 14:18 1662次阅读

    C++的Edison IoT黑盒

    电子发烧友网站提供《C++的Edison IoT黑盒.zip》资料免费下载
    发表于 10-21 14:20 0次下载
    <b class='flag-5'>C++</b><b class='flag-5'>中</b>的Edison IoT黑盒

    C++struct和class的区别?

    C++struct和class的区别是什么?C++struct和class的最大区别在于:         struct的成员默认是公有的, 而class的成员默认是私有的,
    的头像 发表于 03-10 17:41 735次阅读

    C++简史:C++是如何开始的

    的 MISRA C++:2023 博客系列的第二部分。 在这篇博客,我们将深入探讨 C++ 的历史、编程语言多年来的发展历程以及它的下一步发展方向。
    的头像 发表于 01-11 09:00 516次阅读
    <b class='flag-5'>C++</b>简史:<b class='flag-5'>C++</b>是如何开始的

    C++实现类似instanceof的方法

    函数,可实际上C++没有。但是别着急,其实C++中有两种简单的方法可以实现类似Java的instanceof的功能。 在 C++
    的头像 发表于 07-18 10:16 510次阅读
    <b class='flag-5'>C++</b><b class='flag-5'>中</b>实现类似instanceof的方法