C言語におけるvoid*の詳細と応用(1)


voidの意味:
voidの字面は「タイプなし」を意味し、void*は「タイプポインタなし」であり、void*は任意のタイプのデータを指すことができる.
voidはほとんど「注釈」と制限プログラムの役割しかありません.void変数を定義する人はいないので、定義してみましょう.
void a;
この行の文のコンパイル中にエラーが発生し、「illegal use of type'void」というメッセージが表示されます.void aのコンパイルが間違っていなくても、実際の意味はありません.
ポインタp 1とp 2のタイプが同じであれば、p 1とp 2の間で直接値を割り当てることができることはよく知られている.p 1とp 2が異なるデータ型を指す場合、強制型変換演算子を使用して、付与演算子の右側のポインタタイプを左のポインタのタイプに変換する必要があります.
 float *p1;
 int *p2;
 p1 = p2;
 //  p1 = p2       ,
 //  “'=' : cannot convert from 'int *' to 'float *'”,    :
 p1 = (float *)p2;

void*は、強制的なタイプ変換を行うことなく、任意のタイプのポインタを直接割り当てることができます.
void *p1;
 int *p2;
 p1 = p2;

ただし、void*は、強制的なタイプ変換を必要とせずに他のタイプのポインタに付与されてもよいという意味ではありません.[タイプなし](No Type)は[タイプ](Type)を収容し、[タイプ](Type)は[タイプなし](No Type)を収容できないためです.
voidポインタのタイプに注意:
ANSI(American National Standards Institute)規格に従って、voidポインタをアルゴリズム操作することはできません.すなわち、以下の操作はすべて合法ではありません.
void * pvoid;
pvoid++; //ANSI:  
pvoid += 1; //ANSI:  
//ANSI         ,      :                          。
//  :
int *pint;
pint++; //ANSI:  
pint++        sizeof(int)。

しかし、GNUは、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, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );

これにより、任意のタイプのポインタがmemcpyおよびmemsetに転送されます.これは、このメモリがどのタイプであっても、操作対象がメモリ1枚であるため、メモリ操作関数の意味を実質的に表します.もしmemcpyとmemsetのパラメータタイプがvoid*ではなくchar*であれば、それは本当におかしいです!このようなmemcpyとmemsetは明らかに「純粋で、低級な趣味から離れた」関数ではない!
voidの出現は抽象的な必要性のためだけであり,オブジェクト向けの「抽象ベースクラス」の概念を正しく理解すればvoidデータ型も容易に理解できる.抽象ベースクラスにインスタンスを定義できないように、void(voidを「抽象データ型」と呼ぶ)変数を定義することもできません.