0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何理解C++中的void?

jf_78858299 ? 來(lái)源:小余的自習(xí)室 ? 作者:小余的自習(xí)室 ? 2023-03-30 15:01 ? 次閱讀

1.定義

首先void*中的void代表一個(gè)任意的數(shù)據(jù)類(lèi)型,"星號(hào)"代表一個(gè)指針,所以其就是一個(gè)任意數(shù)據(jù)類(lèi)型的指針。

對(duì)于指定數(shù)據(jù)類(lèi)型的指針如int* ,double*等,他們的sizeof都是4個(gè)字節(jié),因?yàn)槎际且粋€(gè)指針,只是指針指向的數(shù)據(jù)類(lèi)型不一致。

C語(yǔ)言是一個(gè)強(qiáng)類(lèi)型的語(yǔ)言, 那么他們之間有什么區(qū)別呢 ?前面一篇文章我們說(shuō)過(guò), 指針+1和-1是和指向數(shù)據(jù)類(lèi)型有關(guān)的 。

假設(shè)指針值為0x00000001,指針類(lèi)型為int類(lèi)型,整數(shù)為n,則計(jì)算出來(lái)的結(jié)果為0x00000001+ n乘以4,這里的4是因?yàn)橹羔橆?lèi)型為int,如果是double,則為0x00000001+ n乘以8. 所以我們使用double類(lèi)型指針+1,地址移動(dòng)了8位,而用int指針+1,地址移動(dòng)了4位,就是這個(gè)道理。

這說(shuō)起來(lái)其實(shí)和數(shù)據(jù)內(nèi)存對(duì)齊有關(guān)。你可以把這里的4和8理解為跳躍力。

那對(duì)于void*呢? 其實(shí)就是一個(gè)未指定跳躍力的指針

那void*的跳躍力又什么時(shí)候指定?在需要使用的時(shí)候指定就可以了,好處: 可以實(shí)現(xiàn)泛型編程,節(jié)省代碼 。

2.void*使用場(chǎng)景

2.1:當(dāng)函數(shù)傳參時(shí)不確定數(shù)據(jù)類(lèi)型時(shí)或者支持多種數(shù)據(jù)類(lèi)型傳遞時(shí)。

代碼如下:

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

該函數(shù)使用一個(gè)type來(lái)表示當(dāng)前參數(shù)void*的類(lèi)型,內(nèi)部通過(guò)type判斷轉(zhuǎn)換的類(lèi)型。

2.2:函數(shù)返回值不需要考慮類(lèi)型,只關(guān)心返回的大小。

如malloc函數(shù):

原型:

void* malloc(size_t size)

代碼使用:

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

可以看到malloc返回值類(lèi)型為void*,其只返回分配內(nèi)存的大小,不關(guān)心分配后的內(nèi)存你是使用int還是double類(lèi)型進(jìn)行劃分.

注意:函數(shù)外部在接收到void*格式的返回值時(shí),需要強(qiáng)轉(zhuǎn)為自己的數(shù)據(jù)類(lèi)型才能使用。

3.void*使用中的注意點(diǎn):

1.使用賦值運(yùn)算符“=”時(shí),void*只能作為左值不能作為右值。

void*作為一個(gè)未指定數(shù)據(jù)類(lèi)型的指針,可以指向任何一個(gè)數(shù)據(jù)類(lèi)型的指針,但是有數(shù)據(jù)類(lèi)型的指針,不能指向一個(gè)void* 的指針。

代碼如下:

int i = 5;
int* pi = &i;
void* pv = pi;
int* pi1 = pv;//編譯錯(cuò)誤,void*類(lèi)型的指針不能初始化為指定類(lèi)型的指針

這其實(shí)是可以理解的:

假設(shè)void*指定了一個(gè)非int類(lèi)型的數(shù)據(jù),如果此時(shí)賦值給int*類(lèi)型的指針,則會(huì)發(fā)生嚴(yán)重的bug**。

2.void*類(lèi)型必須強(qiáng)轉(zhuǎn)為指定類(lèi)型的數(shù)據(jù)才能使用。

void 在未指定類(lèi)型的情況下,是不能直接使用的, 只有在轉(zhuǎn)換為顯示類(lèi)型后才能使用 。 *

代碼如下:

int i = 5;
int* pi = &i;
void* pv = pi;
//cout << *pv << endl;//表達(dá)式必須是指向完整對(duì)象類(lèi)型的指針
cout << *(int*)pv << endl;

代碼中可以看出在未強(qiáng)轉(zhuǎn)為顯示類(lèi)型前,使用void*會(huì)報(bào)表達(dá)式必須是指向完整對(duì)象類(lèi)型的指針.

說(shuō)明void*一定要強(qiáng)轉(zhuǎn)后才能使用.

沒(méi)有強(qiáng)轉(zhuǎn)的void*是沒(méi)有意義的。

那可能有同學(xué)要問(wèn)了,假設(shè)我們并不知道當(dāng)前void*數(shù)據(jù)類(lèi)型,強(qiáng)轉(zhuǎn)錯(cuò)誤了會(huì)發(fā)生什么事。

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;

運(yùn)行結(jié)果:
(int*)pv:0043F724
(double*)pv:0043F724
*(int*)pv:5
*(double*)pv:-9.25596e+61

此時(shí)可以看到雖然pv強(qiáng)轉(zhuǎn)為double后,指針指向的地址和強(qiáng)轉(zhuǎn)為int類(lèi)型指針指向地址是一樣的都是0x0043F724。但是取值后就發(fā)生了異常,因?yàn)閐ouble占用的是8個(gè)字節(jié),所以取值的是后8位字節(jié),所以取到的是一個(gè)錯(cuò)誤的值,實(shí)際只有4個(gè)字節(jié)是有效的。

我們?cè)谑褂胿oid*強(qiáng)轉(zhuǎn)的時(shí)候一定要注意這點(diǎn) 、

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

在C語(yǔ)言中空指針定義方式:

#define NULL ((void*)0)

在C++語(yǔ)言中:

#ifndef NULL
    #ifdef __cplusplus
        #define NULL 0
    #else 
        #define NULL ((void*)0)
    #endif
#endif
可以看到在C語(yǔ)言中NULL代表(void*)0,而在C++中NULL代表的是0,使用nullptr來(lái)表示(void*)0空指針,
所以在C++中推薦使用新標(biāo)準(zhǔn)的nullptr來(lái)初始化一個(gè)空指針。

4.當(dāng)void*作為函數(shù)的參數(shù)類(lèi)型或者返回值類(lèi)型時(shí),說(shuō)明該函數(shù)可以接收或者返回任意類(lèi)型的指針。

代碼如下:

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;

}
運(yùn)行結(jié)果:
5
10.8

代碼中可以看出參數(shù)void* pArgs可以使用任意類(lèi)型的實(shí)參,返回值也可以返回任意類(lèi)型的指針,但是最終需要轉(zhuǎn)換為具體類(lèi)型才能使用。

void*在C++中的作用其實(shí)就是為了實(shí)現(xiàn)泛型編程,和Java中使用Object來(lái)表示是一樣的,所以又稱(chēng)為通用指針和泛指針,不過(guò) C++中大部分情況下會(huì)使用模板編程來(lái)實(shí)現(xiàn)泛型 。

上面_say函數(shù)代碼可以使用下面模板函數(shù)代替:

T _say(T t) {
    return t;
}

區(qū)別在于: 模板編程不需要將強(qiáng)制轉(zhuǎn)換為具體類(lèi)型 ,其使用方式如下:

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

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

未強(qiáng)轉(zhuǎn)也可以直接得出結(jié)果,這是因?yàn)槟0寰幊虝?huì)在編譯器幫我們生成具體的函數(shù)。

調(diào)用了兩次_say會(huì)分別實(shí)現(xiàn):

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

所以運(yùn)行的時(shí)候是調(diào)用了不同的函數(shù),而使用void*的泛型只調(diào)用一個(gè)函數(shù)。

總結(jié)

  • 1.void*是一個(gè)過(guò)渡型的指針狀態(tài),可以代表任意類(lèi)型的指針,取值的時(shí)候需要轉(zhuǎn)換為具體類(lèi)型才能取值。其是處于數(shù)據(jù)類(lèi)型頂端的狀態(tài):

    圖片

  • 2.void* 使用賦值運(yùn)算符“=”賦值時(shí),只能將具體類(lèi)型賦值給void星,不能將void*賦值給具體類(lèi)型。

  • 3.void*一般作為參數(shù)或者返回值來(lái)實(shí)現(xiàn)泛型編程,但是C++中一般考慮使用模板編程來(lái)實(shí)現(xiàn)。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7250

    瀏覽量

    91431
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2118

    瀏覽量

    74909
  • void
    +關(guān)注

    關(guān)注

    0

    文章

    23

    瀏覽量

    10058
收藏 0人收藏

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    C++的結(jié)構(gòu)和類(lèi)

    C++ 仍然是嵌入式開(kāi)發(fā)的少數(shù)??語(yǔ)言,但當(dāng)項(xiàng)目變得太大而無(wú)法有效使用 C 時(shí),開(kāi)發(fā)人員通常會(huì)采用 C++。這些開(kāi)發(fā)人員通常從 C 過(guò)渡到 C++
    發(fā)表于 07-18 17:37 ?965次閱讀

    C語(yǔ)言和C++那些不同的地方

    ++11標(biāo)準(zhǔn)。根據(jù)不同的標(biāo)準(zhǔn),它們的功能也會(huì)有所不同,但是越新的版本支持的編譯器越少,所以本文在討論的時(shí)候使用的C語(yǔ)言標(biāo)準(zhǔn)是C89,C++標(biāo)準(zhǔn)是C++99.我們來(lái)介紹
    的頭像 發(fā)表于 12-07 14:29 ?1496次閱讀
    <b class='flag-5'>C</b>語(yǔ)言和<b class='flag-5'>C++</b><b class='flag-5'>中</b>那些不同的地方

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

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

    C++筆記003:C++從一個(gè)小程序開(kāi)始

    ,暫且這樣理解。<<這個(gè)左移操作符,我們發(fā)現(xiàn)已經(jīng)“變味”了,在C++里面已經(jīng)進(jìn)行功能的改造,跟以前C語(yǔ)言的左移操作符用法不一樣了,這就是C++
    發(fā)表于 03-05 12:51

    C++筆記004:C++類(lèi)通俗點(diǎn)說(shuō)—— C結(jié)構(gòu)體復(fù)習(xí)

    的程序設(shè)計(jì),對(duì)象具有屬性(狀態(tài))和行為,屬性保存在成員變量,行為通過(guò)成員方法(函數(shù))來(lái)實(shí)現(xiàn)。成員方法又是什么?其實(shí)方法和函數(shù)可以理解為一回事。只是在C++
    發(fā)表于 03-05 12:53

    C/C++程序員實(shí)用大全配套代碼

    CC++程序員實(shí)用大全》配套代碼  [涉及平臺(tái)] VC++ [作者] void [文件大小] 629KB  [更新日期] 2005-10-28
    發(fā)表于 02-09 11:18 ?28次下載

    C++簡(jiǎn)介 ppt

    C++簡(jiǎn)介 目錄1.0  本科程在專(zhuān)業(yè)學(xué)習(xí)的地位1.1  程序設(shè)計(jì)語(yǔ)言 1.2  C++前史 1.3  C++ 1.4 
    發(fā)表于 02-24 09:34 ?28次下載

    C語(yǔ)言voidvoid指針深層探索

    1.概述 本文將對(duì)void關(guān)鍵字的深刻含義進(jìn)行解說(shuō),并詳述voidvoid指針類(lèi)型的使用方法與技巧。 2.void的含義 void的字面意
    發(fā)表于 09-21 11:36 ?166次下載

    EE-128:C++的DSP:從C++調(diào)用匯編類(lèi)成員函數(shù)

    EE-128:C++的DSP:從C++調(diào)用匯編類(lèi)成員函數(shù)
    發(fā)表于 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>調(diào)用匯編類(lèi)成員函數(shù)

    淺析C++this指針的理解以及作用

    01 C++程序到C程序的翻譯 想要理解C++語(yǔ)言中的this指針,下面我們做一個(gè)舉例,我們要先把下面的C++代碼轉(zhuǎn)換成
    的頭像 發(fā)表于 06-27 11:24 ?3146次閱讀
    淺析<b class='flag-5'>C++</b><b class='flag-5'>中</b>this指針的<b class='flag-5'>理解</b>以及作用

    C++如何用虛函數(shù)實(shí)現(xiàn)多態(tài)

    01 — C++虛函數(shù)探索 C++是一門(mén)面向?qū)ο笳Z(yǔ)言,在C++里運(yùn)行時(shí)多態(tài)是由虛函數(shù)和純虛函數(shù)實(shí)現(xiàn)的,現(xiàn)在我們看下在C++如何用虛函數(shù)實(shí)現(xiàn)
    的頭像 發(fā)表于 09-29 14:18 ?1898次閱讀

    C++的Edison IoT黑盒

    電子發(fā)燒友網(wǎng)站提供《C++的Edison IoT黑盒.zip》資料免費(fèi)下載
    發(fā)表于 10-21 14:20 ?0次下載
    <b class='flag-5'>C++</b><b class='flag-5'>中</b>的Edison IoT黑盒

    C++struct和class的區(qū)別?

    C++struct和class的區(qū)別是什么?C++struct和class的最大區(qū)別在于: ? ? ? ? struct的成員默認(rèn)是公有的, 而class的成員默認(rèn)是私有的,
    的頭像 發(fā)表于 03-10 17:41 ?963次閱讀

    C++簡(jiǎn)史:C++是如何開(kāi)始的

    的 MISRA C++:2023 博客系列的第二部分。 在這篇博客,我們將深入探討 C++ 的歷史、編程語(yǔ)言多年來(lái)的發(fā)展歷程以及它的下一步發(fā)展方向。
    的頭像 發(fā)表于 01-11 09:00 ?955次閱讀
    <b class='flag-5'>C++</b>簡(jiǎn)史:<b class='flag-5'>C++</b>是如何開(kāi)始的

    C++實(shí)現(xiàn)類(lèi)似instanceof的方法

    函數(shù),可實(shí)際上C++沒(méi)有。但是別著急,其實(shí)C++中有兩種簡(jiǎn)單的方法可以實(shí)現(xiàn)類(lèi)似Java的instanceof的功能。 在 C++
    的頭像 發(fā)表于 07-18 10:16 ?890次閱讀
    <b class='flag-5'>C++</b><b class='flag-5'>中</b>實(shí)現(xiàn)類(lèi)似instanceof的方法

    電子發(fā)燒友

    中國(guó)電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會(huì)員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動(dòng)獲取豐厚的禮品