深入理解void以及void指針的含義
void的含義
void即“無(wú)類(lèi)型”,void *則為“無(wú)類(lèi)型指針”,可以指向任何數(shù)據(jù)類(lèi)型。
void指針使用規(guī)范
①void指針可以指向任意類(lèi)型的數(shù)據(jù),亦即可用任意數(shù)據(jù)類(lèi)型的指針對(duì)void指針賦值。例如:
int *pint;
void *pvoid;
pvoid = pint; /* 不過(guò)不能 pint = pvoid; */
如果要將pvoid賦給其他類(lèi)型指針,則需要強(qiáng)制類(lèi)型轉(zhuǎn)換如:pint = (int *)pvoid;
②在ANSI C標(biāo)準(zhǔn)中,不允許對(duì)void指針進(jìn)行算術(shù)運(yùn)算如pvoid++或pvoid+=1等,而在GNU中則允許,因?yàn)樵谌笔∏闆r下,GNU認(rèn)為void *與char *一樣。sizeof( *pvoid )== sizeof( char ).
void的作用
①對(duì)函數(shù)返回的限定。
②對(duì)函數(shù)參數(shù)的限定。
當(dāng)函數(shù)不需要返回值時(shí),必須使用void限定。例如: void func(int, int);
當(dāng)函數(shù)不允許接受參數(shù)時(shí),必須使用void限定。例如: int func(void)。
由于void指針可以指向任意類(lèi)型的數(shù)據(jù),亦即可用任意數(shù)據(jù)類(lèi)型的指針對(duì)void指針賦值,因此還可以用void指針來(lái)作為函數(shù)形參,這樣函數(shù)就可以接受任意數(shù)據(jù)類(lèi)型的指針作為參數(shù)。例如:
void * memcpy( void *dest, const void *src, size_t len );
void * memset( void * buffer, int c, size_t num );
許多初學(xué)者對(duì)C/C++語(yǔ)言中的void及void指針類(lèi)型不甚理解,因此在使用上出現(xiàn)了一些錯(cuò)誤。本文將對(duì)void關(guān)鍵字的深刻含義進(jìn)行解說(shuō),下面詳述void及void指針類(lèi)型的使用方法與技巧。
1.規(guī)則小心使用void指針類(lèi)型
按照ANSI(AmericanNationalStandardsInstitute)標(biāo)準(zhǔn),不能對(duì)void指針進(jìn)行算法操作,即下列操作都是不合法的:
void*pvoid;
pvoid++;//ANSI:錯(cuò)誤
pvoid+=1;//ANSI:錯(cuò)誤
//ANSI標(biāo)準(zhǔn)之所以這樣認(rèn)定,是因?yàn)樗鼒?jiān)持:進(jìn)行算法操作的指針必須是確定知道其指向數(shù)據(jù)類(lèi)型大小的。
//例如:
int*pint;
pint++;//ANSI:正確
pint++的結(jié)果是使其增大sizeof(int)。
但是大名鼎鼎的GNU(GNU'sNotUnix的縮寫(xiě))則不這么認(rèn)定,它指定void*的算法操作與char*一致。
因此下列語(yǔ)句在GNU編譯器中皆正確:
pvoid++;//GNU:正確
pvoid+=1;//GNU:正確
pvoid++的執(zhí)行結(jié)果是其增大了1。
在實(shí)際的程序設(shè)計(jì)中,為迎合ANSI標(biāo)準(zhǔn),并提高程序的可移植性,我們可以這樣編寫(xiě)實(shí)現(xiàn)同樣功能的代碼:
void*pvoid;
(char*)pvoid++;//ANSI:正確;GNU:正確
(char*)pvoid+=1;//ANSI:錯(cuò)誤;GNU:正確
GNU和ANSI還有一些區(qū)別,總體而言,GNU較ANSI更“開(kāi)放”,提供了對(duì)更多語(yǔ)法的支持。但是我們?cè)谡鎸?shí)設(shè)計(jì)時(shí),還是應(yīng)該盡可能地迎合ANSI標(biāo)準(zhǔn)。
2.規(guī)則二如果函數(shù)的參數(shù)可以是任意類(lèi)型指針,那么應(yīng)聲明其參數(shù)為void*
典型的如內(nèi)存操作函數(shù)memcpy和memset的函數(shù)原型分別為:
void*memcpy(void*dest,constvoid*src,size_tlen);
void*memset(void*buffer,intc,size_tnum);
這樣,任何類(lèi)型的指針都可以傳入memcpy和memset中,這也真實(shí)地體現(xiàn)了內(nèi)存操作函數(shù)的意義,因?yàn)樗僮鞯膶?duì)象僅僅是一片內(nèi)存,而不論這片內(nèi)存是什么類(lèi)型。如果 memcpy和memset的參數(shù)類(lèi)型不是void*,而是char*,那才叫真的奇怪了!這樣的memcpy和memset明顯不是一個(gè)“純粹的,脫離低級(jí)趣味的”函數(shù)!
下面的代碼執(zhí)行正確:
//示例:memset接受任意類(lèi)型指針
int intarray[100];
memset(intarray,0,100*sizeof(int));//將intarray清0
//示例:memcpy接受任意類(lèi)型指針
int intarray1[100], intarray2[100];
memcpy(intarray1,intarray2,100*sizeof(int));//將intarray2拷貝給intarray1
有趣的是,memcpy和memset函數(shù)返回的也是void*類(lèi)型,標(biāo)準(zhǔn)庫(kù)函數(shù)的編寫(xiě)者是多么地富有學(xué)問(wèn)??!
3.規(guī)則三 void不能代表一個(gè)真實(shí)的變量
下面代碼都企圖讓void代表一個(gè)真實(shí)的變量,因此都是錯(cuò)誤的代碼:
voida;//錯(cuò)誤
function(voida);//錯(cuò)誤
void體現(xiàn)了一種抽象,這個(gè)世界上的變量都是“有類(lèi)型”的,譬如一個(gè)人不是男人就是女人(還有人妖?)。
void的出現(xiàn)只是為了一種抽象的需要,如果你正確地理解了面向?qū)ο笾小俺橄蠡?lèi)”的概念,也很容易理解void數(shù)據(jù)類(lèi)型。正如不能給抽象基類(lèi)定義一個(gè)實(shí)例,我們也不能定義一個(gè)void(讓我們類(lèi)比的稱(chēng)void為“抽象數(shù)據(jù)類(lèi)型”)變量。
相關(guān)文章
在C語(yǔ)言中對(duì)utmp文件進(jìn)行查找和寫(xiě)入操作的函數(shù)小結(jié)
這篇文章主要介紹了在C語(yǔ)言中對(duì)utmp文件進(jìn)行查找和寫(xiě)入操作的函數(shù)小結(jié),包括pututline()函數(shù)和getutline()函數(shù)以及getutid()函數(shù),需要的朋友可以參考下2015-08-08利用Qt實(shí)現(xiàn)獲取計(jì)算機(jī)的硬件信息
在開(kāi)發(fā)時(shí),常常會(huì)需要用到計(jì)算機(jī)的相關(guān)信息。利用這些信息,我們可以開(kāi)發(fā)一些輔助模塊。本文將利用Qt實(shí)現(xiàn)獲取計(jì)算機(jī)的硬件信息,感興趣的可以嘗試一下2022-12-12Qt數(shù)據(jù)庫(kù)應(yīng)用之實(shí)現(xiàn)通用數(shù)據(jù)庫(kù)清理
項(xiàng)目如果需要存儲(chǔ)很多日志記錄比如運(yùn)行日志,時(shí)間長(zhǎng)了記錄數(shù)量非常多,數(shù)據(jù)庫(kù)體積不斷增大,對(duì)應(yīng)數(shù)據(jù)庫(kù)表的增刪改查的效率不斷降低,因此需要將早期的數(shù)據(jù)清理。本文將詳細(xì)介紹一下通用數(shù)據(jù)庫(kù)清理的實(shí)現(xiàn),需要的可以參考一下2022-02-02C語(yǔ)言編程C++柔性數(shù)組結(jié)構(gòu)示例講解
這篇文章主要介紹了C語(yǔ)言編程系列中的柔性數(shù)組,文中含有詳細(xì)的示例代碼講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09C語(yǔ)言使用scanf連續(xù)輸入字符串出現(xiàn)的問(wèn)題
這篇文章主要介紹了C語(yǔ)言使用scanf連續(xù)輸入字符串出現(xiàn)的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12C++20中的結(jié)構(gòu)化綁定類(lèi)型示例詳解
這篇文章主要為大家介紹了C++20中的結(jié)構(gòu)化綁定類(lèi)型示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04VisualStudio Community2019在安裝的過(guò)程中無(wú)法進(jìn)入安裝界面的解決方法
這篇文章主要介紹了VisualStudio Community2019在安裝的過(guò)程中無(wú)法進(jìn)入安裝界面的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03