Petite présentation de sys/queue.h

date
26 / 9 / 2009
date
C
comments
2

Dans vos programmes C, il arrive très fréquemment d'utiliser des listes chaînée (de toutes sortes), afin de ne pas avoir à recréer le monde à chaque fois vous pouvez utiliser les macros super pratiques de queue(3). Voici une petite introduction à l'utilisation de sys/queue.h avant d'aller se plonger dans le man pour aller plus loin.

Avec sys/queue.h , vous pouvez manipuler facilement quatres sortes de listes :

  • Listes simplement chainées (SLIST) de type pile
  • Listes doublement chainées (LIST) de type pile
  • Listes simplement chainées (STAILQ) de type file
  • Listes doublement chainées (TAILQ) de type file

Voici un exemple de SLIST :

Le header :

#ifndef HEADER_H
#define HEADER_H

#include <sys/queue.h>

typedef struct MaStruct {
    /* ici on met nos elements par exemple : */
    char *str;

    /*
     * On déclare notre liste avec SLIST_ENTRY qui est equivalente à
     * struct { struct MaStruct *sle_next; } next;
     */

    SLIST_ENTRY(MaStruct) next;
} MaStruct;

#endif /* HEADER_H */

Ensuite voyons comment manipuler cette liste :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "header.h"

int
main(void)
{
    /* SLIST_HEAD crée une variable pour acceder à notre liste */
    SLIST_HEAD(, MaStruct) head;

    /* on crée un element MaStruct */
    MaStruct *p;

    /* On l'initialise à NULL */
    SLIST_INIT(&head);

    p = malloc(sizeof(*p));
    p->str = malloc(sizeof(char) * 10);
    strcpy(p->str, "blah");

    /* On insere p dans la SLIST */
    SLIST_INSERT_HEAD(&head, p, next);

    /* On empile un deuxième element */
    p = malloc(sizeof(*p));
    p->str = malloc(sizeof(char) * 10);
    strcpy(p->str, "blu");

    SLIST_INSERT_HEAD(&head, p, next);

    /*
     * Il est très facile de parcourir la liste
     * que ce soit pour du traitement ou de
     * la libération de mémoire
     */
    SLIST_FOREACH(p, &head, next) {
        /* ici p est l'element courant */
        printf("element : %s\n", p->str);
    }

    /* exemple de libération */
    while (!SLIST_EMPTY(&head))
    {
        p = SLIST_FIRST(&head);
        SLIST_REMOVE_HEAD(&head);
        free(p->str);
        free(p);
    }

    return 0;
}

Parmis les macros interessantes pour les SLIST il y a :

SLIST_FIRST(&head);                /* renvoie la tête de liste */
SLIST_REMOVE_HEAD(&head, next);    /* supprime la tete de liste */
SLIST_EMPTY(&head); /* renvoie vrai si la liste est vide */

Ben entendu, il y a beaucoup plus de possibilités avec LIST et TAILQ... Mais globalement vous devriez avoir compris le principe.

La lecture de sys/queue.h devrait vous éclairer pour comprendre comment marchent toutes ces macros, c'est assez facile à comprendre si vous avez (comme moi) un niveau moyen en C.

Voyez aussi ce papier d'iMil.

Previous post

Nouveau blog

Next post

Spamd ourgl

Comments: 2

ksh 11 / 11 / 2009 at 0:29

Salut, en effet il y a une erreur. Je corrige ça, merci :-)

chris 9 / 11 / 2009 at 19:28

Bonjour,

L'exemple de "nettoyage" de la liste n'est pas correct:

SLIST_FOREACH(p, &head, next) { / ici p est l'element courant / printf("element : %sn", p->str); free(p->str); free(p); }

SLIST_FOREACH fait: for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)

Le pb c'est que le free(p) va libérer l'espace occupé par p, mais ensuite à l'itération suivante, on fait p = p->next.sle_next; ...

Add a comment

captcha



Comments are formatted using markdown syntax.