C言語でのvoidポインタの使用法

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 *を使用します。

おすすめ

転載: blog.csdn.net/qq_27575841/article/details/109731252