IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

container_of dans kernel.h


Sujet :

C

  1. #1
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 4
    Par défaut container_of dans kernel.h
    Bonjour, je suis en train d'étudier la gestion des listes chaînées sous linux (list.h) et on se rend compte qu'il y a une macro "container_of".

    Cette macro est définie dans "kernel.h" mais je n'arrive pas à comprendre son fonctionnement et particulierement le "((type *)0)->member )" il semblerait qu'on cast 0 mais dans quelle utilité ?

    Pouvez-vous m'indiquer, s'il vous plait, le fonctionnement de cette macro.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    /**
     * container_of - cast a member of a structure out to the containing structure
     *
     * @ptr:        the pointer to the member.
     * @type:       the type of the container struct this is embedded in.
     * @member:     the name of the member within the struct.
     *
     */
    #define container_of(ptr, type, member) ({			\
            const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
            (type *)( (char *)__mptr - offsetof(type,member) );})
    J'ai une autre question, pour ne pas utiliser les pointeurs NULL, ils utilisent deux pointeurs, je comprends pas le choix de ces adresses spécifiquement et le danger du pointeur NULL.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    /*
     * These are non-NULL pointers that will result in page faults
     * under normal circumstances, used to verify that nobody uses
     * non-initialized list entries.
     */
    #define LIST_POISON1  ((void *) 0x00100100)
    #define LIST_POISON2  ((void *) 0x00200200)
    Merci.

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    container_of() : J'ai du mal à comprendre, car je ne connais pas ce que fait typeof, ni trop comment cette syntaxe peut marcher :
    Pour moi, un compilateur est supposé rejeter ceci. Mais je ne connais pas aussi bien la norme qu'Emmanuel.

    Pour les autres macros, c'est simple: Cala sert à détecter les pointeurs non-initialisés d'une liste, donc on ne peut pas utiliser NULL car NULL est sans doute une valeur valide pour initialiser...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre éclairé Avatar de telliam
    Inscrit en
    Octobre 2006
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 63
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    /**
     * container_of - cast a member of a structure out to the containing structure
     *
     * @ptr:        the pointer to the member.
     * @type:       the type of the container struct this is embedded in.
     * @member:     the name of the member within the struct.
     *
     */
    #define container_of(ptr, type, member) ({			\
            const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
            (type *)( (char *)__mptr - offsetof(type,member) );})
    Je vais essayer d'expliquer ce que j'ai compris :
    1er ligne :
    ((type*)0)->member : on veut récupérer le champ member d'une structure type mais vu qu'on a pas de variable de ce type la sous la main ( et qu'on peut s'en passer) on caste l'adresse 0 comme si il y avait une variable à cette adresse la ( en plus,en 0 on est , dans les plupart des systemes, sur qu'il y a rien).
    Ensuite on applique typeof sur ce membre pour récupérer son type, ce qui permet de créér un pointeur __mptr contenant l'addresse ptr.

    2eme ligne :
    offsetof(type,member) permet de récupérer l'offset du champ member dans uns structure de type type. On retire ce décalage à l'adresse __mptr pour récupérer le container. CCQFD

  4. #4
    Membre éclairé Avatar de telliam
    Inscrit en
    Octobre 2006
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 63
    Par défaut
    Citation Envoyé par Médinoc
    container_of() : J'ai du mal à comprendre, car je ne connais pas ce que fait typeof, ni trop comment cette syntaxe peut marcher :
    Pour moi, un compilateur est supposé rejeter ceci. Mais je ne connais pas aussi bien la norme qu'Emmanuel.
    pour moi, x=({a;b}); aura comme effet x=b;

  5. #5
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    En C++, typeof( ((type*)NULL)->member ) aurait sans doute été remplacé par un typeof( type::member ). Je suppose que comme sizeof(), typeof() n'évalue jamais l'expression.

    On aurait pu remplacer le tout par void* et la macro aurait toujours marché, mais on n'aurait plus de contrôle de type... (qui vérifie que ptr est bien du type typeof(member) *)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Membre éclairé Avatar de telliam
    Inscrit en
    Octobre 2006
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 63
    Par défaut
    Citation Envoyé par Médinoc
    En C++, typeof( ((type*)NULL)->member ) aurait sans doute été remplacé par un typeof( type::member ). Je suppose que comme sizeof(), typeof() n'évalue jamais l'expression.

    On aurait pu remplacer le tout par void* et la macro aurait toujours marché, mais on n'aurait plus de contrôle de type... (qui vérifie que ptr est bien du type typeof(member) *)
    void* beurk ,c'est qd mm plus propre d'utiliser le bon type qd tu utilises un pointeur.

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Si typeof est standard, OK.
    Sinon, c'est un argument en faveur du void*...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre éclairé Avatar de telliam
    Inscrit en
    Octobre 2006
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 63
    Par défaut
    Citation Envoyé par Médinoc
    Si typeof est standard, OK.
    Sinon, c'est un argument en faveur du void*...
    à mon avis les personnes qui savent ce qui est standard de ce qui ne l'est pas sont de plus en plus rare, mon bon je m'écarte un peu du sujet

  9. #9
    Futur Membre du Club
    Inscrit en
    Octobre 2006
    Messages
    4
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 4
    Par défaut
    Merci Médinoc pour les pointeurs et la correspondance avec le C++
    Et Merci Telliam !

    Donc si j'ai compris, les deux pointeurs servent à trouver un chaînons non (ou plus) dans la liste chaînée.

    Pour la première ligne du container_of, le but serait donc de créer un pointeur d'une structure que l'on ne connait pas (donc toutes les structures possibles)

    Dites mois si je me trompe.

    Merci encore !

  10. #10
    Nouveau candidat au Club
    Inscrit en
    Novembre 2006
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 2
    Par défaut
    Citation Envoyé par guillaume-u
    Donc si j'ai compris, les deux pointeurs servent à trouver un chaînons non (ou plus) dans la liste chaînée.
    Non!
    Le but de ces pointeurs est de permettre au noyau de détecter une mauvaise utilisation des macros sur les listes chainées.
    C'est a dire que si un module essaye d'accéder aux autres éléments d'une liste à partir d'un élément qui a été retiré de la liste l'erreur sera détectée (OOOps ou kernel panic)

    Citation Envoyé par guillaume-u
    Pour la première ligne du container_of, le but serait donc de créer un pointeur d'une structure que l'on ne connait pas (donc toutes les structures possibles)
    et
    Citation Envoyé par Médinoc
    container_of() : J'ai du mal à comprendre, car je ne connais pas ce que fait typeof, ni trop comment cette syntaxe peut marcher :
    Pour moi, un compilateur est supposé rejeter ceci.
    Hum... explications:
    pour le "typeof" c'est un mot clé, au même titre que "if", "while"...
    Voir ici pour tout: http://gcc.gnu.org/onlinedocs/gcc/Typeof.html
    En rapide: il permet de déclarer une macro qui ne dépende pas du type des éléments passés à la macro.

    pour la syntaxe: NOOONNNN !!
    la syntaxe ({ a ; b;}) est standard en C: c'est un bloc de code, contenant deux instructions : "a" et "b" qui seront exécutées successivement.

    et si elle est utilisée ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    #define test( a, b )   ({ a ; b;}) 
     
    int c = 1;
    int result = test( c++, c+3 );
    ceci nous donne (si je ne me trompe pas:
    c=2
    result=5

    utilisez gcc avec le flag "-E" pour voir le résultat de la transformation du code par le préprocesseur.


    Enfin pour la macro "container_of" :
    Elle sert à récupérer un pointeur sur la structure contenant member, dont nous connaissons l'adresse.
    en effet, "offsetof(type,member)" donne l'offset de "member" dans la structure qui le contient.

    Le but est de pouvoir, par exemple, implémenter des listes chainées sans s'occuper du contenu des éléments.

    en effet, il suffit au programmeur de créer ses éléments comme une structure dont un des membres est du type " struct list_head* "

    pour faire une liste chainée d'entiers:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    struct chainon {
        int val;
        struct list_head entry;
    };
    pour créer la liste (vide):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    struct list_head head;
    INIT_LIST_HEAD( &head );
    pour ajouter des éléments:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    struct chainon un_chainon;
    struct chainon autre_chainon;
     
    list_add( &un_chainon.entry, &head );
    On remarque que ce n'est pas notre "struct chainon" qui a été ajouté à la liste, mais le membre "entry" de notre structure.

    Dès lors, comment accéder à notre entier à partir d'un élément de la liste? grace à la macro container_of.
    IMPORTANT: utiliser list_entry(), et non pas directement container_of. (pour des raisons de lisibilité et de maintenabilité)


    CQFD
    Vala, amusez vous bien.

  11. #11
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par drizzt1611
    la syntaxe ({ a ; b;}) est standard en C: c'est un bloc de code, contenant deux instructions : "a" et "b" qui seront exécutées successivement.
    C'est une extension de gcc. Ce n'est pas standard.

  12. #12
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Par défaut
    Salut,

    On a eu une discussion tout récemment sur ce sujet. Tu peux lire le post:
    http://www.developpez.net/forums/sho...d.php?t=234455

    Sinon, un excellent article traite de ceci dans GNU Linux Magazine France du mois de septembre. Mais l'essentiel est dans le post référencé ci-dessus.

    Mujigkalement

    Thierry
    "The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
    "If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow

    FAQ-Python FAQ-C FAQ-C++

    +

  13. #13
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet
    C'est une extension de gcc. Ce n'est pas standard.
    Tout comme typeof, me semble-t-il

  14. #14
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Bizarre, gcc accepte cette extension même si je compile en -ansi...
    Par contre, sous Visual, aussi bien en C qu'en C++, ça grouille de syntax error...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  15. #15
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $ cat medinoc.c
    int f()
    {
        return ({ 1+2; 3+4;});
    }
    $ gcc -ansi -pedantic-errors medinoc.c
    medinoc.c: In function `f':
    medinoc.c:3: ISO C forbids braced-groups within expressions

  16. #16
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    OK, c'est -pedantic que j'avais oublié.
    Merci
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. Observer des points dans l'espace kernel (gaussien)
    Par acx01b dans le forum Téléchargez
    Réponses: 0
    Dernier message: 29/04/2010, 01h44
  2. liste chainée dans la programmation kernel
    Par rufa11 dans le forum Debian
    Réponses: 0
    Dernier message: 09/02/2009, 23h12
  3. Changer version du Kernel dynamiquement (dans un chroot)
    Par asher256 dans le forum Administration système
    Réponses: 3
    Dernier message: 04/01/2008, 15h39
  4. sous-section Linux Kernel dans la section développement Linux
    Par kromartien dans le forum Evolutions du club
    Réponses: 1
    Dernier message: 13/04/2007, 09h36
  5. Bug dans unstable => Kernel Panic
    Par Tchetch dans le forum Debian
    Réponses: 1
    Dernier message: 11/01/2007, 12h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo