void及void指針含義的深刻解析


void的含義

void即“無類型”,void *則為“無類型指針”,能夠指向不論什么數據類型。

void
指針使用規范
①void
指針能夠指向隨意類型的數據,亦就可以用隨意數據類型的指針對void指針賦值。比如:
int * pint;
void *pvoid;
pvoid = pint; /* 
只是不能 pint= pvoid; */
假設要將pvoid賦給其它類型指針,則須要強制類型轉換如:pint= (int *)pvoid;

ANSIC標准中,不同意對void指針進行算術運算如pvoid++pvoid+=1等,而在GNU中則同意,由於在缺省情況下,GNU覺得void *char *一樣。sizeof(*pvoid )== sizeof( char).

void
的作用
對函數返回的限定。
對函數參數的限定。
當函數不須要返回值時,必須使用void限定。比如: void func(int, int);
當函數不同意接受參數時,必須使用void限定。比如: int func(void)

由於void指針能夠指向隨意類型的數據,亦就可以用隨意數據類型的指針對void指針賦值,因此還能夠用void指針來作為函數形參,這樣函數就能夠接受隨意數據類型的指針作為參數。比如:
void * memcpy( void *dest, const void *src, size_t len );
void * memset( void * buffer, int c, size_t num);

------------------------------------------------------------------------------


1. 綜述

很多剛開始學習的人對C/C++語言中的voidvoid指針類型不甚理解,因此在使用上出現了一些錯誤。本文將對voidkeyword的深刻含義進行講解,並詳述voidvoid指針類型的用法與技巧。

2.void的含義

  void的字面意思是“無類型”,void*則為“無類型指針”,void*能夠指向不論什么類型的數據。void差點兒僅僅有“凝視”和限制程序的作用,由於從來沒有人會定義一個void變量,讓我們試着來定義:
void a;
  這行語句編譯時會出錯,提示“illegal use of type’void’”。只是,即使voida的編譯不會出錯,它也沒有不論什么實際意義。
  void真正發揮的作用在於:
  (1)對函數返回的限定;
  (2)對函數參數的限定。
   眾所周知,假設指針p1p2的類型相同,那么我們能夠直接在p1p2間互相賦值;假設p1p2指向不同的數據類型,則必須使用強制類型轉換運算符把賦值運算符右邊的指針類型轉換為左邊指針的類型。
  比如:
float * p1;
in t* p2;
p1 = p2;
  當中p1 = p2語句會編譯出錯,提示“’=’:cannotconvertfrom’int *’to’float *’”,必須改為:
p1=(float*)p2;
void*則不同,不論什么類型的指針都能夠直接賦值給它,無需進行強制類型轉換:
void * p1;
int * p2;
p1 = p2;
  但這並不意味着,void*也能夠無需強制類型轉換地賦給其它類型的指針。由於“無類型”能夠包容“有類型”,而“有類型”則不能包容“無類型”。道理非常簡單,我們能夠說“男人和女人都是人”,但不能說“人是男人”或者“人是女人”。以下的語句編譯出錯:
void * p1;
int * p2;
p2 = p1;


  提示“’=’:cannotconvertfrom’void*’to’int*’”

3.void的使用

  以下給出 void keyword的使用規則:
  規則一假設函數沒有返回值,那么應聲明為 void 類型
  在 C 語言中,凡不加返回值類型限定的函數,就會被編譯器作為返回整型值處理。可是很多程序猿卻誤以為其為 void 類型。比如:
add(inta,intb)
{
return a+b;
}
int main(int argc,char * argv[])
{
printf(/"2+3=%d/",add(2,3));
}
  程序執行的結果為輸出:
   2+3=5
  這說明不加返回值說明的函數的確為 int 函數。
  林銳博士《高質量 C/C++ 編程》中提到:“ C++ 語言有非常嚴格的類型安全檢查,不同意上述情況(指函數不加類型聲明)發生”。可是編譯器並不一定這么認定,譬如在 VisualC++6.0 中上述 add 函數的編譯無錯也無警告且執行正確,所以不能寄希望於編譯器會做嚴格的類型檢查。
  因此,為了避免混亂,我們在編寫 C/C++ 程序時,對於不論什么函數都必須一個不漏地指定其類型。假設函數沒有返回值,一定要聲明為 void 類型。這既是程序良好可讀性的須要,也是編程規范性的要求。另外,加上 void 類型聲明后,也能夠發揮代碼的“自凝視”作用。代碼的“自凝視”即代碼能自己凝視自己。  [Page]
規則二假設函數無參數,那么應聲明其參數為 void
  在 C++ 語言中聲明一個這種函數:
int function(void)
{
return1;
}
  則進行以下的調用是不合法的:
function(2);
  由於在 C++ 中,函數參數為 void 的意思是這個函數不接受不論什么參數。
我們在 TurboC2.0 中編譯:
#include"stdio.h"
fun()
{
return1;
}
main()
{
printf(/"%d/",fun(2));
getchar();
}
  編譯正確且輸出 1 ,這說明,在 C 語言中,能夠給無參數的函數傳送隨意類型的參數,可是在 C++ 編譯器中編譯相同的代碼則會出錯。在 C++ 中,不能向無參數的函數傳送不論什么參數,出錯提示“’ fun’:functiondoesnottake1parameters”
  所以,不管在 C 還是 C++ 中,若函數不接受不論什么參數,一定要指明參數為 void
  規則三小心使用 void 指針類型
  依照 ANSI(AmericanNationalStandardsInstitute) 標准,不能對 void 指針進行算法操作,即下列操作都是不合法的:
void * pvoid;
pvoid ++;//ANSI
:錯誤
pvoid += 1;//ANSI
:錯誤
ANSI
標准之所以這樣認定,是由於它堅持:進行算法操作的指針必須是確定知道其指向數據類型大小的。 比如:
int * pint;
pint ++;//ANSI
:正確
pint++ 的結果是使其增大 sizeof(int)
可是大名鼎鼎的 GNU(GNU’sNotUnix 的縮寫 ) 則不這么認定,它指定 void *  的算法操作與 char *  一致。
因此下列語句在 GNU 編譯器中皆正確:
pvoid ++;//GNU
:正確
pvoid += 1;//GNU
:正確
   pvoid++ 的執行結果是其增大了 1
  在實際的程序設計中,為迎合 ANSI 標准,並提高程序的可移植性,我們能夠這樣編寫實現相同功能的代碼:
void * pvoid;
(char*)pvoid ++;//ANSI
:正確; GNU :正確
(char*)pvoid += 1;//ANSI
:錯誤; GNU :正確
   GNU ANSI 另一些差別,整體而言, GNU ANSI 更“開放”,提供了對很多其它語法的支持。可是我們在真實設計時,還是應該盡可能地迎合 ANSI 標准。
  規則四假設函數的參數能夠是隨意類型指針,那么應聲明其參數為 void*
  典型的如內存操作函數 memcpy memset 的函數原型分別為:
void * memcpy(void*dest,constvoid*src,size_tlen);

void * memset(void*buffer,intc,size_tnum);


  這樣,不論什么類型的指針都能夠傳入memcpymemset中,這也真實地體現了內存操作函數的意義,由於它操作的對象僅僅是一片內存,而不論這片內存是什么類型。假設 memcpymemset的參數類型不是void*,而是char*,那才叫真的奇怪了!這種memcpymemset明顯不是一個“純粹的,脫離低級趣味的”函數!


以下的代碼執行正確:
//
演示樣例:memset接受隨意類型指針
int intarray[100];[Page]
memset(intarray,0,100*sizeof(int));//
intarray0
//
演示樣例:memcpy接受隨意類型指針
int intarray1[100],intarray2[100];
memcpy(intarray1,intarray2,100*sizeof(int));//
intarray2拷貝給intarray1
  有趣的是,memcpymemset函數返回的也是void*類型,標准庫函數的編寫者是多么地富有學問啊!
  規則五void不能代表一個真實的變量
  以下代碼都企圖讓void代表一個真實的變量,因此都是錯誤的代碼:
void a;//
錯誤
function(void a);//
錯誤
  void體現了一種抽象,這個世界上的變量都是“有類型”的,譬如一個人不是男人就是女人(還有人妖?)。
  void的出現僅僅是為了一種抽象的須要,假設你正確地理解了面向對象中“抽象基類”的概念,也非常easy理解void數據類型。正如不能給抽象基類定義一個實例,我們也不能定義一個void(讓我們類比的稱void為“抽象數據類型”)變量。

4.總結

  小小的void蘊藏着非常豐富的設計哲學,作為一名程序設計人員,對問題進行深一個層次的思考必定使我們受益匪淺。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM