L'utilisation du pointeur void en langage C

Dans le processus de développement en langage C, vous rencontrez souvent un pointeur spécial comme void *, qui est facile à ignorer par les novices. En fait, void * est très puissant. Voici quelques exemples plus courants.

1. Utilisé comme pointeur générique recevant n'importe quel type de données

Void * est utilisé pour pointer vers une adresse spécifique sans se soucier du type de données stockées sur cette adresse. Par exemple, les fonctions courantes telles que memcpy utilisent void *, et le prototype de fonction est le suivant:

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

Les void * des et void * src peuvent ici recevoir n'importe quel type de pointeur de type de données. Comme il s'agit d'une copie mémoire, les paramètres d'entrée ne doivent pas être limités au type de pointeurs transmis, ce qui est logiquement très raisonnable.

2. Application et version de mémoire dynamique

La valeur de retour de la fonction d'application de mémoire dynamique est généralement void *. Si l'application réussit, elle renvoie la première adresse du bloc de mémoire appliqué. Si l'application échoue, elle renvoie un pointeur nul NULL, ce qui équivaut à (void * ) 0. Le prototype de la fonction malloc de la bibliothèque C est le suivant:

void *malloc(size_t size) 

Généralement, après avoir demandé la mémoire, il sera utilisé avec la coercition de type pointeur, comme indiqué ci-dessous.

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

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

3. Association de données privées

L'utilisation de void * pour associer des données privées est une technique de programmation courante, largement répandue sous Linux. Ce qui suit est un extrait du code de "Explication détaillée du développement de pilotes de périphériques Linux" par M. Song Baohua, en conservant la partie principale. Il y a un void * private_data dans la structure du fichier struct. Utilisez le pointeur private_data du fichier struct dans globalmem_open pour enregistrer l'adresse du périphérique correspondant, puis tant que le pointeur de structure de fichier est obtenu plus tard, il peut être indirectement via le private_data membre du pointeur de structure de fichier Le périphérique correspondant est obtenu, tel que la fonction 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;
}

Non seulement Linux, mais aussi void * peut souvent être vu dans certains RTOS. Par exemple, lorsqu'un thread ou un minuteur est créé, il a souvent besoin d'une fonction d'entrée ou d'une fonction de rappel de délai d'expiration, et le paramètre d'entrée de ces fonctions est souvent un vide *. Utilisez ces vides * si nécessaire pour simplifier le code et réduire le couplage.

Je suppose que tu aimes

Origine blog.csdn.net/qq_27575841/article/details/109731252
conseillé
Classement