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 :

Problème avec un struct et uint_32_t


Sujet :

C++

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut Problème avec un struct et uint_32_t
    bonjour,

    j'ai un problème qui me sidère complètement... J'ai un struct composé un peu dans ce genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    typedef monstruct1*{
       u_int8_t val1;
       u_int8_t val2;
    } monstruct1_t;
     
    typedef monstruct2*{
       u_int8_t val1;
       u_int32_t val2;
    } monstruct2_t;
    Lorsque je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    monstruct1.val1 = 0xAA;
    monstruct1.val2 = 0xFF;
    La mémoire contient bien : AA FF

    en revanche si je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    monstruct2.val1 = 0xAA;
    monstruct2.val2 = 0xFFFFFFFF;
    La mémoire contient : AA 00 00 00 FF FF FF FF... d'où j'en tire que j'ai 3 fois 0x00 qui se sont insérés entre mon val1 et mon val2.
    Si je mets val2 en u_int16_t j'obtiens : AA 00 FF FF... je n'ia plus qu'un 0x00 qui s'est inséré.

    Je précise que je suis sous g++ sous Mac os x en 64 bits. Est-ce que quelqu'un comprend quelque chose à tout ca ??? Je suis complètement incapable de construire un pauvre struct même pas compliqué à cause de ca !!!

    Merci pour votre aide
    Tristan

  2. #2
    Membre chevronné Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 043
    Points : 2 234
    Points
    2 234
    Par défaut
    probablement du padding!
    J'avais lancé un thread la dessus ici
    Arrange ta structure dans ce sens la et observe si il y a une différence:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    typedef monstruct2*{
       u_int32_t val2;
       u_int8_t val1;
       u_int8_t val3;
       u_int8_t val4;
       u_int8_t val5;
    
    
    } monstruct2_t;
    Homer J. Simpson


  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut
    Ah ouais on dirait que tu as raison, lorsque je mets mets valeurs dans l'ordre décroissant il ne semble plus y avoir de problème. Par contre ce qui me gène c'est que je construis un paquet grâce à une succession de struct... je vais être obligé de faire des contorsions avec mes paquets si je ne peux pas simplement mapper mes struct et mon paquet.

    Y a-t-il une autre solution ?

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut
    Encore que je remarque une chose tout de même, mon struct est censé faire 33 octets et un sizeof m'en donne 36 (chandelles...).

    Son prototype est celui-ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
            u_int32_t val1;
    	u_int32_t val2;
    	u_int32_t val3;
    	u_int16_t val4;
    	u_int8_t val5;
    	u_int8_t val6;
    	u_int8_t val7;
    	u_int8_t val8[16];

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut
    Et pour le coup, les 3 octets surnuméraires sont placés à la fin de la struct...

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Comme l'a dit Astraya, c'est une question de padding, dont la raison d'être est « l'alignement mémoire » des informations.

    Je ne connais pas encore l'architecture 64 bits en détails, mais sur les 32 bits au moins, si ta mémoire et le bus qui la désert sont larges de 32 bits, alors chaque mot mémoire fait 32 bits. MAIS, l'unité d'adressage de ton processeur, elle, est resté sur huit bits, de sorte que chaque adresse mémoire référence un octet.

    Ça signifie que si tu veux lire un mot de 32 bits localisé à une adresse multiple de 4, il sera lu en une seule fois, mais que, par contre, si tu veux lire le même mot à une adresse non-multiple de 4, le micro-processeur va être obligé d'aller lire de façon transparente deux demi-mots, donc faire deux transactions bus au lieu d'une, et d'aller extraire dans chacun la partie intéressante, puis de recoller les morceaux pour reconstituer la donnée qui t'intéresse.

    Par conséquent, si tu n'es pas limité en mémoire, le compilateur va tâcher autant que faire se peut, de calculer des offsets multiples de 4 pour chacun des membres de ta structure s'ils dépassent huit bits, étant entendu que les instances de ta structure, comme les autres variables, seront alignées de la même façon. Pour les instances d'un octet, il faut de toutes façons l'extraire du mot lu, donc sa position importe peu.

    Tu peux utiliser « #pragma pack » pour tenter de tasser tes membres dans tes structures si c'est nécessaire, mais ce n'est absolument pas portable ni standard. Donc, le mieux est encore de concevoir des programmes qui ne soient pas sensibles à ce problème.

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par esteban Voir le message
    Par contre ce qui me gène c'est que je construis un paquet grâce à une succession de struct...
    Très mauvaise idée :
    1/ les problème d'alignement commencent à te sauter à la figure et se poseront à chaque plateforme cible/option de compilation ;
    2/ une fois que tu en auras terminé avec les problèmes d'alignement.... tu vas découvrir les problèmes d'endianess ;
    3/ ensuite tu te trouveras sur des plateformes exotiques où tes acrobaties pour maitriser les alignements (pragma pack et autres) finiront par provoquer des adressages interdits.

    Bref pour construire un paquet vu comme une suite d'octet, construit le en considérant l'octet et pas en essayant de mapper une structure sur une zone mémoire.

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    230
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2002
    Messages : 230
    Points : 132
    Points
    132
    Par défaut
    Ok j'ai réussi à résoudre (temporairement) le problème en utilisant le pragma pack. Mais je vais suivre vos conseils car je travaille sur une application industrialisée... le but est donc que ca fonctionne...
    je vais utiliser des struct comme conteneur et ensuite je vais positionner mes valeurs dans un tableau de char pour construire le paquet à la main...

    Merci pour vos conseils.

  9. #9
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Citation Envoyé par esteban Voir le message
    Ok j'ai réussi à résoudre (temporairement) le problème en utilisant le pragma pack. Mais je vais suivre vos conseils car je travaille sur une application industrialisée... le but est donc que ca fonctionne.. je vais utiliser des struct comme conteneur et ensuite je vais positionner mes valeurs dans un tableau de char pour construire le paquet à la main...
    Si tu dois sérialiser tes structures. N'utilises pas un tableau de char, car l'existence de ce type est garanti par la norme, mais pas son format. A contrario, les tailles des types définis dans <stdint.h> sont fixées, mais ces types peuvent ne pas être disponibles si la plate-forme cible ne sait pas les gérer.

    Si c'est toi qui définit le protocole de communication, que tu n'es pas trop limité en espace mémoire, et que la vitesse n'est pas un problème (soit parce que ta connexion est rapide, soit parce que la quantité de données à émettre est réduite), le plus simple est de les envoyer au format texte et de les reconvertir à la réception.

  10. #10
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Si tu dois sérialiser tes structures. N'utilises pas un tableau de char, car l'existence de ce type est garanti par la norme, mais pas son format. A contrario, les tailles des types définis dans <stdint.h> sont fixées, mais ces types peuvent ne pas être disponibles si la plate-forme cible ne sait pas les gérer.
    Considérant que la dernière fois qu'on en a causé, VC++ n'avait pas de stdint.h et que s'il a a passer sur une machine avec un char qui fait autre chose que 8 bits, il va falloir regarder les choses en détails (les IO sont définies en terme de char pour commencer), j'ai l'impression qu'utiliser char est plus portable qu'utiliser int8_t, au moins en pratique (et la portabilité, c'est avant tout un problème pratique).
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  11. #11
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Considérant que la dernière fois qu'on en a causé, VC++ n'avait pas de stdint.h
    Oops ! Je n'avais pas fait attention au fait que l'on est ici dans le forum C++ et pas C. Honte à moi. Cela dit, j'ai cité ce header car il utilise uint8_t dans ses messages.

    … et que s'il a a passer sur une machine avec un char qui fait autre chose que 8 bits, il va falloir regarder les choses en détails (les IO sont définies en terme de char pour commencer), j'ai l'impression qu'utiliser char est plus portable qu'utiliser int8_t, au moins en pratique (et la portabilité, c'est avant tout un problème pratique).
    Je suis d'accord. Cependant, « char » est souvent synonyme « d'octet » dans l'esprit de beaucoup de gens, et ce en toute bonne foi. Il est toujours utile de rappeler les définitions exactes pour éviter les surprises.

  12. #12
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Oops ! Je n'avais pas fait attention au fait que l'on est ici dans le forum C++ et pas C. Honte à moi.
    Il n'y a pas de honte. Mais c'est bien au support par MS que je faisais allusion, tout aussi inexistant en C qu'en C++ aux dernières nouvelles, pas au fait que stdint.h est du C99 et pas encore du C++ (pour autant que je puisse le constater, il est bien supporté en pratique en C++ en dehors de chez MS, même s'il faut définir __STDC_LIMIT_MACROS pour avoir les macros donnant les limites, ce qui ne sera plus nécessaire avec C++0X)

    Cela dit, j'ai cité ce header car il utilise uint8_t dans ses messages.
    Il utilise u_int8_t, mais considérant qu'il y a aussi "typedef monstruct2*{", et qu'il indique utiliser gcc sous MacOS c'est peut-être une faute de frappe.

    Je suis d'accord. Cependant, « char » est souvent synonyme « d'octet » dans l'esprit de beaucoup de gens, et ce en toute bonne foi. Il est toujours utile de rappeler les définitions exactes pour éviter les surprises.
    Je l'ai fait assez souvent pour que ne pas être d'accord serait un signe d'un changement bizarre d'opinions.

    Le fond de ma remarque est que les IO en C et en C++ sont définies en terme de char, donc sérialiser ou désérialiser en vue d'IO, c'est transformer vers ou depuis une séquence de char. Si le protocole est défini en terme d'octets et que les chars ne font pas 8 bits, il va falloir regarder comment l'implémentation fait la transformation et quoi qu'on fasse, les garanties de portabilité sont faibles.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  13. #13
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Il n'y a pas de honte. Mais c'est bien au support par MS que je faisais allusion, tout aussi inexistant en C qu'en C++ aux dernières nouvelles,
    Visual 2010 possède <cstdint>. Ce code compile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #include <cstdint>
    std::uint8_t ui8;
    Idem pour stdint.h en c :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #include <stdint.h>
    uint8_t ui8;
    Remarque : char n'est pas byte ... mais lorsqu'il est et si je dois l'utiliser, je préfère unsigned char.
    Remarque 2 : en réseau, il n'est pas toujours possible de sérialiser vers une chaîne de caractère (protocole imposé ou contrainte de taille de transmission par expl).

  14. #14
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Visual 2010 possède <cstdint>.
    Il aura fallu le temps (10 ans après C99 et inttypes.h est une pratique plus vieille -- stdint.h a été introduit en C99 pour fournir un sous-ensemble de inttypes.h pertinent pour les implémentations freestanding). Mais c'est quand même une bonne nouvelle.

    Je me demande si c'est le résultat de l'implémentation de C++0X ou d'une décision d'implémenter C99 aussi (voir p.e. <stdbool.h>, <complex.h> et <tgmath.h> en C, entêtes demandés par C++0X mais n'ayant qu'un intérêt que compatibilité avec le C -- et des choses comme inline, la sémantique du C est différente de celle de C++, ou les VLA dans le langage).
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  15. #15
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Remarque : char n'est pas byte
    Si, char est un byte, mais pas un octet.

    ... mais lorsqu'il est et si je dois l'utiliser, je préfère unsigned char.
    Sur le fond, je partage ta préférence. Il ne reste plus qu'à changer la définition du C et du C++

    Qu'on le veuille ou non, char est utilisé pour trois choses différentes dans la définition de ces langages:
    - élément de base du codage des caractères,
    - unité d'adressage de la mémoire,
    - unité de transfert des IO

    Le mot byte a été défini au départ pour le premier sens (dans un contexte historique ou l'unité d'adressage était bien souvent le mot et une vision des IO unifiée pas encore en vue)
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

Discussions similaires

  1. Problème avec realloc et struct
    Par _SamSoft_ dans le forum Bibliothèque standard
    Réponses: 38
    Dernier message: 27/12/2007, 10h13
  2. Réponses: 22
    Dernier message: 29/01/2005, 11h29
  3. Problème avec [b]struct[/b]
    Par Bouziane Abderraouf dans le forum CORBA
    Réponses: 2
    Dernier message: 17/07/2002, 10h25
  4. Problème avec la mémoire virtuelle
    Par Anonymous dans le forum CORBA
    Réponses: 13
    Dernier message: 16/04/2002, 16h10

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