看板 uefacool
作者 標題 [Cpro] void 指針
時間 2011年12月02日 Fri. PM 02:50:24
http://www.lslnet.com/linux/f/docs1/i36/big5267553.htm
2006年6月6日
void 指針
看到有些人對void指針不太清楚,我就試著解釋一下,權當拋磚引玉。
大家都知道int *pint是定義了一個指針變量,這個變量裡面放的是一個地址,而這個地址裡面放的是一個int型的數值。
char *pchar是定義了一個指針變量,這個變量裡面放的是一個地址,而這個地址裡面放的是一個char型的數值。
以此類推……我們也知道在32位計算機上,一般sizeof(pint)是4,也就是說指針變量p的大小是4個字節,每個地址用32位來表示。
我們還知道一般sizeof(int)也是4,因為尋址的最小單元是字節,也就是一個int型數據一共佔用了4個地址空間。
比如定義int i;假設從首地址到末地址分別為:10000,10001,10002,10003(這裡為了討論問題的方便,不考慮bigendian,little endian的問題,有興趣的可以查找有關資料)。然後int *pint = &i,因為i佔用了4個地址,那麼p裡面放的是什麼呢?p裡面放的是變量i的首地址,也就是10000。
我們可以用*pint來表示i,當我們這樣做時*pint = 10;編譯器是怎麼解釋的呢?編譯器的解釋是向從10000地址開始的4個字節裡面放入整數10。可能你又要問了,編譯器又是怎麼知道是從10000地址開始的4個字節呢?是的,編譯器知道它該這麼做,因為pint是一個指針而且它的內容10000,還有p是一個指向int型變量的指針,還因為sizeof(int)是4,所以它可以確保做上面的事情。
好了,囉哩囉嗦的說了關於int類型指針這麼多,對別的類型指針也是一樣。
現在該說說void指針了。void *pvoid;這樣定義後,我們必須明確的知道,p也是一個指針,sizeof(pvoid)或sizeof(void *)也是4。給它賦值後,它的內容也是一個地址。比如我們把上面pint賦值給pvoid, pvoid = (void *)pint;現在pvoid和pint的內容完全一樣,也是10000。可當你這樣使用時,*pvoid = 1;編譯器就會報錯了。
問題就在於pvoid是無類型的指針,也就是它不指向任何類型,你間接引用時,編譯器從10000地址開始,要到哪個地址才能結束呢?編譯器不知道這些事情,所以它會報錯。當我們明確知道pvoid指向的是什麼類型,就可以用強制類型轉換把pvoid轉換為那個類型的指針,例如 *(int *)pvoid = 1;這樣就可以了,此時i的值為1。
現在你應該清楚void指針的概念了吧。任何類型的指針都可以賦值給void指針,你也可以把void指針轉換成任何類型(當然,你把它轉換成並不是它實際指向的類型,結果不可預測。比如你把int型指針賦予void指針,然後把void指針強制轉換成doube型指針,並間接引用它,這樣的結果不可預測)所以使用時應該把void指針轉換成它實際指向的類型。使用void指針增加了程序的靈活性,
但一定要謹慎使用。
這是我剛剛寫的,由於是上班,也沒有很好的考慮,如果有錯誤,歡迎指正!下面附帶一些測試代碼,環境aix5l,gcc3.3
#include <stdio.h>;
int main()
{
int *pint;
int i = 10;
pint = &i
void *pvoid;
pvoid = (void *)pint;
printf("sizeof(void *) = %d\n",sizeof(void*));//sizeof(void *) = 4
printf("pint = %p,pvoid = %p\n",pint,pvoid);
printf("(int*)i = %d\n",*pint);
printf("(void*)i = %d\n",*(int *)pvoid);
printf("(void*)i = %d\n",*pvoid);//不能通過編譯
*(int *)pvoid = 1;
printf("%d\n",i);
*(long *)pvoid = 1;//可以編譯通過,結果也正確
printf("%d\n",i);
*(short *)pvoid = 1;//可以編譯通過,結果不正確
printf("%d\n",i);
return 0;
}
int main()
{
int *pint;
int i = 10;
pint = &i
void *pvoid;
pvoid = (void *)pint;
printf("sizeof(void *) = %d\n",sizeof(void*));//sizeof(void *) = 4
printf("pint = %p,pvoid = %p\n",pint,pvoid);
printf("(int*)i = %d\n",*pint);
printf("(void*)i = %d\n",*(int *)pvoid);
printf("(void*)i = %d\n",*pvoid);//不能通過編譯
*(int *)pvoid = 1;
printf("%d\n",i);
*(long *)pvoid = 1;//可以編譯通過,結果也正確
printf("%d\n",i);
*(short *)pvoid = 1;//可以編譯通過,結果不正確
printf("%d\n",i);
return 0;
}
--
※ 作者: uefangsmith 時間: 2011-12-02 14:50:24
※ 編輯: uefangsmith 時間: 2012-05-05 23:43:38
※ 看板: uefacool 文章推薦值: 0 目前人氣: 0 累積人氣: 23
回列表(←)
分享