The usage of void pointer in C language

In the process of developing in C language, you often encounter a special pointer like void*, which is easy to be ignored by novices. In fact, void* is very powerful. Here are a few more common examples.

1. Used as a generic, receiving pointers to any data type

Void* is used to point to a specific address without worrying about what type of data is stored on this address. For example, common functions such as memcpy use void*, and the function prototype is as follows:

void *memcpy(void *des, void *src, size_t n)

The void *des and void *src here can receive any type of data type pointer. Since it is a memory copy, the input parameters should not be restricted to what type of pointers are passed in, which is logically very reasonable.

2. Dynamic memory application and release

The return value of the dynamic memory application function is generally void*. If the application is successful, it returns the first address of the applied memory block. If the application fails, it returns a null pointer NULL, which is equivalent to (void *)0. The prototype of the malloc function of the C library is as follows:

void *malloc(size_t size) 

Generally, after applying for memory, it will be used together with pointer type coercion, as shown below.

typedef struct 
{
    char    *name;
    int     age;
    ...
}animal, *animal_t;

animal_t dog = (animal_t )malloc(sizeof(animal));
if(!dog)
{
    printf("malloc failed\n");
}

3. Private data association

Using void* to associate private data is a common programming technique, which is widespread in Linux. The following is a snippet of code from "Detailed Explanation of Linux Device Driver Development" written by Mr. Song Baohua, keeping the core part. There is a void* private_data in the struct file structure. Use the private_data pointer of the struct file in globalmem_open to record the address of the corresponding device, then as long as the file structure pointer is obtained later, it can be indirectly through the private_data member of the file structure pointer The corresponding device is obtained, such as the globalmem_read function.

#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;
}

Not only Linux, but also void* can often be seen in some RTOSs. For example, when a thread or timer is created, it often needs an entry function or a timeout callback function, and the input parameter of these functions is often a void*. Use these void* when necessary to simplify the code and reduce coupling.

Guess you like

Origin blog.csdn.net/qq_27575841/article/details/109731252