深入理解C語(yǔ)言的void*
一、void* 的類型任意性
void* 是一種通用指針類型。它可以指向任意類型的數(shù)據(jù)。例如,它可以指向一個(gè)整數(shù)(int)、一個(gè)浮點(diǎn)數(shù)(float)、一個(gè)字符(char)或者一個(gè)結(jié)構(gòu)體等。在C語(yǔ)言中,當(dāng)你使用void*指針時(shí),你不需要在編譯時(shí)指定它將指向的數(shù)據(jù)類型。這使得void* 在一些需要通用指針的場(chǎng)景下非常有用,比如在內(nèi)存分配函數(shù)malloc中返回的就是void*類型的指針。因?yàn)閙alloc函數(shù)不知道用戶將要分配的內(nèi)存用于存儲(chǔ)哪種類型的數(shù)據(jù),所以它返回一個(gè)void*指針,用戶可以根據(jù)自己的需要將其轉(zhuǎn)換為特定類型的指針。
例如:
void* ptr = malloc(10 * sizeof(int)); int* intPtr = (int*)ptr; // 將void*指針轉(zhuǎn)換為int*指針
在這個(gè)例子中,void*指針 ptr 可以指向分配的內(nèi)存區(qū)域,然后通過(guò)類型轉(zhuǎn)換將其轉(zhuǎn)換為int*指針,用于存儲(chǔ)整數(shù)數(shù)組。
二、編譯器對(duì) void* 的類型檢查
編譯時(shí)不做類型檢查(針對(duì)void*本身)編譯器在編譯時(shí)不會(huì)對(duì)void*指針本身進(jìn)行類型檢查。因?yàn)?nbsp;void* 表示“未知類型”的指針,編譯器無(wú)法知道它實(shí)際指向的數(shù)據(jù)類型。所以,當(dāng)你對(duì)void指針進(jìn)行操作(如賦值等)時(shí),編譯器不會(huì)檢查其指向的數(shù)據(jù)類型是否正確。例如,你可以將一個(gè)指向整數(shù)的指針賦值給void指針,也可以將一個(gè)指向字符的指針賦值給void*指針,編譯器都不會(huì)報(bào)錯(cuò)。
int a = 10; char b = 'k'; void* vp1 = &a; void* vp2 = &b;
在這個(gè)例子中,vp1和vp2都是void*指針,分別指向了不同類型的變量a和b,編譯器不會(huì)對(duì)這種賦值操作進(jìn)行類型檢查。
三、需要顯式類型轉(zhuǎn)換
當(dāng)你想要使用 void* 指針訪問(wèn)其中的某個(gè)值時(shí),通常需要先將其轉(zhuǎn)換為特定類型的指針,然后通過(guò)轉(zhuǎn)換后的指針來(lái)訪問(wèn)值。在轉(zhuǎn)換時(shí),你需要明確指定目標(biāo)類型,編譯器會(huì)對(duì)轉(zhuǎn)換后的指針類型進(jìn)行檢查。例如,如果你想通過(guò) void* 指針訪問(wèn)一個(gè)整數(shù)的值,你需要先將其轉(zhuǎn)換為 int* 指針。
例如:
void* vp = malloc(sizeof(int)); *(int*)vp = 20; // 先將void*轉(zhuǎn)換為int*,然后通過(guò)int*指針賦值
在這個(gè)例子中,vp是一個(gè)void*指針,指向分配的內(nèi)存。在給這塊內(nèi)存賦值之前,需要先將其轉(zhuǎn)換為int*指針。如果轉(zhuǎn)換的目標(biāo)類型和實(shí)際存儲(chǔ)的數(shù)據(jù)類型不匹配,可能會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。 比如,如果這塊內(nèi)存實(shí)際上存儲(chǔ)的是一個(gè)浮點(diǎn)數(shù),而你將其轉(zhuǎn)換為int*指針并訪問(wèn),可能會(huì)得到錯(cuò)誤的結(jié)果或者引發(fā)程序異常。編譯器在轉(zhuǎn)換時(shí)會(huì)檢查語(yǔ)法是否正確(如是否有合適的類型轉(zhuǎn)換操作),但對(duì)于類型轉(zhuǎn)換的正確性(即是否符合程序的實(shí)際邏輯)主要依賴于程序員的正確使用。
占用的字節(jié)
一、32位系統(tǒng)
在32位系統(tǒng)中,void* 指針通常占據(jù)4個(gè)字節(jié)。這是因?yàn)?2位系統(tǒng)中的內(nèi)存地址空間是2的32次方(即4GB),用4個(gè)字節(jié)(32位)就可以表示一個(gè)內(nèi)存地址。例如,在一個(gè)32位的Windows系統(tǒng)或者32位的Linux系統(tǒng)上,無(wú)論是void指針,還是其他類型的指針(如int、char*等),它們都占據(jù)4個(gè)字節(jié)。這4個(gè)字節(jié)存儲(chǔ)的是一個(gè)內(nèi)存地址,這個(gè)地址可以指向進(jìn)程地址空間內(nèi)的任意位置。
二、64位系統(tǒng)
在64位系統(tǒng)中,void* 指針通常占據(jù)8個(gè)字節(jié)。64位系統(tǒng)有更大的內(nèi)存地址空間,理論上可以達(dá)到2的64次方字節(jié)。因此,需要用8個(gè)字節(jié)(64位)來(lái)表示一個(gè)完整的內(nèi)存地址。在64位系統(tǒng)上,無(wú)論是 void* 指針,還是其他類型的指針,它們的大小都是8個(gè)字節(jié)。這使得64位系統(tǒng)能夠訪問(wèn)更大的內(nèi)存空間,支持更大的數(shù)據(jù)處理和更復(fù)雜的程序運(yùn)行。
四、總結(jié)
通過(guò)我們上面的介紹, 我們發(fā)現(xiàn) void* 在 C 語(yǔ)言中是經(jīng)常使用的, 它主要有下面這幾個(gè)方案:
- 第一個(gè)方案就是作為結(jié)構(gòu)體的字段, 這樣我們可以去表示對(duì)應(yīng)的范型字段
- 函數(shù)的參數(shù), 或者返回值, 但是我覺(jué)得這種最好少用, 因?yàn)閷?dǎo)致對(duì)應(yīng)的接口不夠明確
- 各種內(nèi)存相關(guān)的函數(shù), 這其實(shí)就是一個(gè)很奇妙的東西, 因?yàn)樵诓僮飨到y(tǒng)級(jí)別, 我們并不知道這塊內(nèi)存到底是什么類型的變量
約定: 當(dāng)我們?cè)谑褂?nbsp;void* 的時(shí)候, 我們最好弄清楚當(dāng)前這個(gè)指針指向的信息, 可以通過(guò)明確的變量名來(lái)完成
到此這篇關(guān)于深入理解C語(yǔ)言的void*的文章就介紹到這了,更多相關(guān)C語(yǔ)言 void*內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Dijkstra算法最短路徑的C++實(shí)現(xiàn)與輸出路徑
今天小編就為大家分享一篇關(guān)于Dijkstra算法最短路徑的C++實(shí)現(xiàn)與輸出路徑,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02
C語(yǔ)言實(shí)現(xiàn)帶頭雙向循環(huán)鏈表
本文主要介紹了C語(yǔ)言實(shí)現(xiàn)帶頭雙向循環(huán)鏈表,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C++簡(jiǎn)單實(shí)現(xiàn)與分析二叉搜索樹(shù)流程
二叉搜索樹(shù)作為一個(gè)經(jīng)典的數(shù)據(jù)結(jié)構(gòu),具有鏈表的快速插入與刪除的特點(diǎn),同時(shí)查詢效率也很優(yōu)秀,所以應(yīng)用十分廣泛。本文將詳細(xì)講講二叉搜索樹(shù)的C++實(shí)現(xiàn),需要的可以參考一下2022-08-08
C語(yǔ)言程序設(shè)計(jì)50例(經(jīng)典收藏)
本篇文章是對(duì)C語(yǔ)言程序設(shè)計(jì)的50個(gè)小案例進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易三子棋
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易三子棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07

