天天看點

C語言中void*詳解及應用

 void在英文中作為名詞的解釋為“空虛;空間;空隙”;而在c語言中,void被翻譯為“無類型”,相應的void *為“無類型指針”。void似乎隻有“注釋”和限制程式的作用,當然,這裡的“注釋”不是為我們人提供注釋,而是為編譯器提供一種所謂的注釋。

1.對函數傳回的限定,這種情況我們比較常見。

2.對函數參數的限定,這種情況也是比較常見的。

一般我們常見的就是這兩種情況:

當函數不需要傳回值值時,必須使用void限定,這就是我們所說的第一種情況。例如:void func(int a,char *b)。

當函數不允許接受參數時,必須使用void限定,這就是我們所說的第二種情況。例如:int func(void)。

1.void指針可以指向任意類型的資料,就是說可以用任意類型的指針對void指針對void指針指派。例如:

      int *a;

      void *p;

      p=a;

     如果要将void指針p賦給其他類型的指針,則需要強制類型轉換,就本例而言:a=(int

*)p。在記憶體的配置設定中我們可以見到void指針使用:記憶體配置設定函數malloc函數傳回的指針就是void

*型,使用者在使用這個指針的時候,要進行強制類型轉換,也就是顯式說明該指針指向的記憶體中是存放的什麼類型的資料(int

*)malloc(1024)表示強制規定malloc傳回的void*指針指向的記憶體中存放的是一個個的int型資料。

2.在ansi

c标準中,不允許對void指針進行一些算術運算如p++或p+=1等,因為既然void是無類型,那麼每次算術運算我們就不知道該操作幾個位元組,例如

char型操作sizeof(char)位元組,而int則要操作sizeof(int)位元組。而在gnu中則允許,因為在預設情況下,gnu

認為void *和char *一樣,既然是确定的,當然可以進行一些算術操作,在這裡sizeof(*p)==sizeof(char)。

void幾乎隻有“注釋”和限制程式的作用,因為從來沒有人會定義一個void變量,讓我們試着來定義:

void a;

這行語句編譯時會出錯,提示“illegal use of type 'void'”。即使void a的編譯不會出錯,它也沒有任何實際意義。

    衆所周知,如果指針p1和p2的類型相同,那麼我們可以直接在p1和p2間互相指派;如果p1和p2指向不同的資料類型,則必須使用強制類型轉換運算符把指派運算符右邊的指針類型轉換為左邊指針的類型。

 而void *則不同,任何類型的指針都可以直接指派給它,無需進行強制類型轉換

但這并不意味着,void *也可以無需強制類型轉換地賦給其它類型的指針。因為“無類型”可以包容“有類型”,而“有類型”則不能包容“無類型”。

小心使用void指針類型:

按照ansi(american national standards institute)标準,不能對void指針進行算法操作,即下列操作都是不合法的:

但是gnu則不這麼認定,它指定void *的算法操作與char *一緻。是以下列語句在gnu編譯器中皆正确: 

在實際的程式設計中,為迎合ansi标準,并提高程式的可移植性,我們可以這樣編寫實作同樣功能的代碼:

gnu和ansi還有一些差別,總體而言,gnu較ansi更“開放”,提供了對更多文法的支援。但是我們在真實設計時,還是應該盡可能地迎合ansi标準。 如果函數的參數可以是任意類型指針,那麼應聲明其參數為void *

注:void指針可以任意類型的資料,可以在程式中給我們帶來一些好處,函數中形為指針類型時,我們可以将其定義為void指針,這樣函數就可以接受任意類型的指針。如:

典型的如記憶體操作函數memcpy和memset的函數原型分别為:

如果memcpy和memset的參數類型不是void *,而是char

*,那才叫真的奇怪了!這樣的memcpy和memset明顯不是一個“純粹的,脫離低級趣味的”函數!void的出現隻是為了一種抽象的需要,如果你正

确地了解了面向對象中“抽象基類”的概念,也很容易了解void資料類型。正如不能給抽象基類定義一個執行個體,我們也不能定義一個void(讓我們類比的稱

void為“抽象資料類型”)變量。

繼續閱讀