C言語でのvoid *の詳細な説明と適用

ボイドは、英語では「空、スペース、ギャップ」として名詞として解釈され、C言語では、ボイドは「タイプなし」として翻訳され、対応するボイド*は「型なしポインター」です。Voidは、「コメント」とプログラムの制限の役割しかないようです。もちろん、ここでの「コメント」は、コメントを提供するためではなく、コンパイラーにいわゆるコメントを提供するためのものです。

この記事のアドレス:http://www.cnblogs.com/archimedes/p/c-void-point.html、転載のソースアドレスを示してください。

voidの役割:
1。関数の戻りの制限、この状況は私たちにとってより一般的です。

2.関数パラメータの制限、この状況も比較的一般的です。

一般に、これら2つの状況は一般的です。

関数が値を返す必要がない場合は、voidで修飾する必要があります。これを最初のケースと呼びます。例:void func(int a、char * b)。

関数がパラメーターを受け入れることが許可されていない場合は、void修飾を使用する必要があります。これは、2番目のケースと呼ばれます。例:int func(void)。

voidポインターの使用規則:1。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標準では、p ++やp + = 1などのvoidポインターに対する一部の算術演算は許可されていません。これは、voidが型指定されていないため、charなどの各算術演算で操作するバイト数がわからないためです。 typeはsizeof(char)バイトで動作しますが、intはsizeof(int)バイトで動作する必要があります。GNUでは、デフォルトでvoid *がchar *と同じであると見なされるため、許可されます。確かであるため、sizeof(* p)== sizeof(char)の場合、もちろんいくつかの算術演算を実行できます。

ボイドには、プログラムを「コメント」して制限する機能しかありません。ボイド変数を定義した人は誰もいないため、次のように定義してみましょう。

ボイドa;

このステートメント行をコンパイルすると、「タイプ「void」の不正使用」を促すエラーが発生します。void aのコンパイルでエラーが発生しなくても、実用的な意味はありません。

ご存知のとおり、ポインターp1とp2が同じタイプの場合、p1とp2の間に値を直接割り当てることができます.p1とp2が異なるデータ型を指している場合は、キャスト演算子を使用してポインターを変換する必要があります代入演算子の右側の型左ポインタの型です。

 float *p1;
 int *p2;
 p1 = p2;

// p1 = p2ステートメントはコンパイルエラーになります、
//プロンプト "'=': 'int *'から 'float *'"に変換できません。p1
=(float *)p2;
およびvoid * isに変更する必要があります異なる、強制なしで、任意のタイプのポインタを直接割り当てることができます

void *p1;
int *p2;
p1 = p2;

ただし、これは、void *をキャストせずに他のタイプのポインターにも割り当てることができるという意味ではありません。「notype」には「typed」を含めることができ、「typed」には「notype」を含めることはできません。

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 *として宣言する必要があります。

注:voidポインターは任意のタイプのデータにすることができるため、プログラムにいくつかの利点があります。関数がポインタータイプの場合、関数が任意のタイプのポインターを受け入れることができるように、voidポインターとして定義できます。といった:

典型的なメモリ操作関数memcpyおよびmemsetの関数プロトタイプは次のとおりです。

void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );

このようにして、任意のタイプのポインタをmemcpyとmemsetに渡すことができます。これは、メモリのタイプに関係なく、操作するオブジェクトがメモリの一部にすぎないため、メモリ操作関数の意味を真に反映しています(C言語を参照)。実装ジェネリックプログラミング)。memcpyとmemsetのパラメータタイプがvoid *ではなくchar *である場合、それは本当に奇妙です!このようなmemcpyとmemsetは、明らかに「純粋な、低レベルの楽しみから」の機能ではありません。voidの出現は抽象的な必要性のためだけです。オブジェクト指向の「抽象的な基本クラス」の概念を正しく理解していれば、voidデータ型を理解するのは簡単です。抽象基本クラスのインスタンスを定義できないのと同じように、void(voidを「抽象データ型」と同様に呼ぶ)変数を定義することはできません。

転載元:https://www.cnblogs.com/wuyudong/p/c-void-point.html

おすすめ

転載: blog.csdn.net/weixin_42692164/article/details/113616383