El uso del puntero vacío en lenguaje C

En el proceso de desarrollo en lenguaje C, a menudo se encuentra un puntero especial como void *, que es fácil de ignorar por los principiantes. De hecho, void * es muy poderoso. A continuación, se muestran algunos ejemplos más comunes.

1. Usado como genérico, recibiendo punteros a cualquier tipo de datos.

Void * se utiliza para señalar una dirección específica sin preocuparse por el tipo de datos que se almacenan en esta dirección. Por ejemplo, funciones comunes como memcpy usan void *, y el prototipo de función es el siguiente:

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

El void * des y void * src aquí pueden recibir cualquier tipo de puntero de tipo de datos Dado que es una copia de memoria, los parámetros de entrada no deben limitarse al tipo de punteros que se pasan, lo cual es lógicamente muy razonable.

2. Aplicación y lanzamiento de memoria dinámica

El valor de retorno de la función de aplicación de memoria dinámica generalmente es nulo *. Si la aplicación tiene éxito, devuelve la primera dirección del bloque de memoria aplicado. Si la aplicación falla, devuelve un puntero nulo NULL, que es equivalente a (void * ) 0. El prototipo de la función malloc de la biblioteca C es el siguiente:

void *malloc(size_t size) 

Generalmente, después de solicitar la memoria, se utilizará junto con la coerción de tipo puntero, como se muestra a continuación.

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

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

3. Asociación de datos privados

El uso de void * para asociar datos privados es una técnica de programación común, que está muy extendida en Linux. El siguiente es un fragmento del código de "Explicación detallada del desarrollo de controladores de dispositivos Linux" por el Sr. Song Baohua, manteniendo la parte central. Hay un vacío * private_data en la estructura del archivo struct. Utilice el puntero private_data del archivo struct en globalmem_open para registrar la dirección del dispositivo correspondiente, y siempre que el puntero de la estructura del archivo se obtenga más tarde, puede ser indirectamente a través de private_data miembro del puntero de estructura de archivo Se obtiene el dispositivo correspondiente, como la función 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;
}

No solo Linux, sino que también se puede ver void * en algunos RTOS. Por ejemplo, cuando se crea un hilo o temporizador, a menudo se necesita una función de entrada o una función de devolución de llamada de tiempo de espera, y el parámetro de entrada de estas funciones suele ser vacío * Utilice estos vacíos * cuando sea necesario para simplificar el código y reducir el acoplamiento.

Supongo que te gusta

Origin blog.csdn.net/qq_27575841/article/details/109731252
Recomendado
Clasificación