C言語で開発する過程で、初心者には無視されやすいvoid *のような特別なポインターに遭遇することがよくあります。実際、void *は非常に強力です。ここにいくつかのより一般的な例があります。
1.ジェネリックとして使用され、任意のデータ型へのポインタを受け取ります
Void *は、特定のアドレスに保存されているデータの種類を気にせずに、特定のアドレスを指すために使用されます。たとえば、memcpyなどの一般的な関数はvoid *を使用し、関数プロトタイプは次のとおりです。
void *memcpy(void *des, void *src, size_t n)
ここでのvoid * desとvoid * srcは、任意のタイプのデータ型ポインターを受け取ることができます。これはメモリコピーであるため、入力パラメーターは、渡されるポインターのタイプに限定されるべきではありません。これは論理的に非常に合理的です。
2.動的メモリのアプリケーションとリリース
動的メモリアプリケーション関数の戻り値は通常void *です。アプリケーションが成功すると、適用されたメモリブロックの最初のアドレスが返されます。アプリケーションが失敗すると、(void * )0。Cライブラリのmalloc関数のプロトタイプは次のとおりです。
void *malloc(size_t size)
通常、メモリを申請した後は、以下に示すように、ポインタ型強制と一緒に使用されます。
typedef struct
{
char *name;
int age;
...
}animal, *animal_t;
animal_t dog = (animal_t )malloc(sizeof(animal));
if(!dog)
{
printf("malloc failed\n");
}
3.プライベートデータの関連付け
void *を使用してプライベートデータを関連付けることは、Linuxで広く使用されている一般的なプログラミング手法です。以下は、Song Baohua氏による「Linuxデバイスドライバー開発の詳細な説明」のコードの抜粋であり、コア部分を保持しています。構造体ファイル構造体にvoid * private_dataがあります。globalmem_openの構造体ファイルのprivate_dataポインターを使用して、対応するデバイスのアドレスを記録します。ファイル構造体ポインターが後で取得される限り、private_dataを介して間接的に取得できます。ファイル構造体ポインターのメンバーglobalmem_read関数など、対応するデバイスが取得されます。
#define DEVICE_NUM 10
struct globalmem_dev
{
struct cdev cdev;
...
};
struct globalmem_dev *global_devp;
static int __init globalmem_init(void)
{
int i;
/* 分配设备号等操作 */
...
/* 为global_devp申请DEVICE_NUM个globalmem_dev内存大小的空间 */
global_devp = kzalloc(sizeof(struct globalmem_dev) * DEVICE_NUM, GFP_KERNEL);
if(!global_devp )
return -1;
for(i = 0; i < DEVICE_NUM; i++)
{
/* 将申请的DEVICE_NUM个设备添加到字符设备节点中 */
globalmem_setup_cdev(global_devp + i, i);
}
return 0;
}
static int globalmem_open(struct inode *inode,struct file *filp)
{
/* 在globalmem_setup_cdev中已经添加到字符设备节点了 */
struct globalmem_dev *dev = container_of(inode->i_dedv,
struct globalmem_dev, cdev);
filp->private_data = dev;
}
static ssize_t globalmem_read(struct file *filp, char __user *buf,
size_t size, loff_t *ppos)
{
struct globalmem_dev *dev = filp->private_data;
}
一部のRTOSでは、Linuxだけでなくvoid *もよく見られます。たとえば、スレッドやタイマーを作成するときに、エントリ関数やタイムアウトコールバック関数が必要になることが多く、これらの関数の入力パラメータはvoidであることがよくあります。 *。コードを単純化し、結合を減らすために、必要に応じてこれらのvoid *を使用します。