爲啥C語言中的void *被稱作萬能指針

在進行c語言開發過程中,有時候會遇到void *這種數據類型。比如:

void * memcpy(void * dest, const void * src, size_t n);
void * memmove(void * dest, const void * src, size_t n);

對於指針類型來說,不管是int *,char * 還是void*,亦或是struct stru*,這種類型都是值一個地址,在32位環境下,都是一個32位的無符號整形數值,表示一個地址。既然都是一個地址,爲啥還弄這麼多種類型呢?

其實,對於int *a,或者char * b,抑或 void *c來說。這裏的*表示這是一個指針類型,用這玩意定義的變量(如,a,b,c)都是一個地址,都是一個uint32_t類型(在32位環境下)。*前面的數據類型呢?作用有2個:(1)便於人看和記憶,讓人知道這玩意定義的那個地址以及後續指定長度的數據怎麼解析;(2)給編譯器用的,讓它知道那個地址及後面的連續的指定長度的數據如何解析。這裏所謂的指定長度,就和*前面的數據類型有關啦。

對於int *a來說,a表示1個地址如0x12345678(4個字節),int表示從0x12345678開始的4個字節(siezof(int)=4)需要用int來解釋,或者說那4個連續字節表示一個int類型數據;對於char* b來說,b表示0x00112345這個地址,而char表示從b開始的連續1個字節需要用char類型來解析。

這樣下來,對於void * c呢?c表示一個地址0x00112233,它後面的數據怎麼解析呢?有多長呢?都不知道。因爲c語言沒有規定void多長,佔幾個字節等等。所以呢?c這個變量是沒法直接用的。

那你又說了,既然沒法用,那這玩意就是廢物,定義它幹啥?

你想想C++中的基類和虛函數。明白了嗎?這玩意沒法用,但可以充當一個類似基類功能的變量啊。上面void *c,c表示一個4字節的地址。在32位環境下,不管是哪種數據類型,*都是表示一個32位的地址。那我定義一個void *c,是不是可以把其他任何類型賦值給它呢?你想要啥類型,就用啥類型替換void不就行了?

類似上面的memcpy,雖然參數是void *,但是你把char*放進去實例化,是可以用的,你把執行一塊int區域的int*放進去,也是可以的。這樣,你就不用再給每種類型的數據拷貝分別頂一個函數了。只需要一個函數,就可以實現各種數據類型的內存拷貝。

上面其實就是說了可以把void*強制轉換成任意數據類型的指針,但是反過來呢?

把任意數據類型的指針強制轉換成void*可以嗎?例如,我定義了一個copy(int *dest,const int * src,int len)實現把src指向的存儲int類型數據的區域拷貝len個數據(實際是4*len字節)到dest指向的區域。那我這時候有一個void *a, void *b。我是否可以執行copy(a,b,len)呢?

顯然是不行的!爲啥?對於b來說,b開始的連續區域,單位是多少呢?雖然要拷貝len個數據,但是每個數據多長呢?沒法確定。所以無法執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章