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 struct et union


Sujet :

C

  1. #1
    Candidat au Club
    Inscrit en
    Avril 2009
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Avril 2009
    Messages : 2
    Points : 2
    Points
    2
    Par défaut Problème struct et union
    Bonjour,

    pour faire une communication USB j'ai créer la structure suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
     
    //Structure pour les données mémoire
        struct Memoire
        {
            unsigned char iAdresse_I2C;
            unsigned int iAdresse;
            unsigned char iNb_Octet;
            unsigned char iDonnees[57];
        };
     
    union Donnees_Produit
    {
            //Pour l'affectation de toute la mémoire
            unsigned char pDonnees[63];
     
            //Structure pour les données mémoire
            Memoire pMemoire;
    };
    dans mon code j'affecte la structure mémoire de la structure Donnees_Produit avec les informations suivantes :
    iAdresse_I2C = 0xA6
    iAdresse = 0x12345678
    iNb_Octet = 0x57
    iDonnees = données à écrire

    ce que j'attends c'est d'avoir dans mon tableau pDonnes[63] :

    0xA6
    0x78
    0x56
    0x34
    0x12
    0x57
    ...

    or

    pDonnes[63] contient
    0xA6
    0x00
    0x00
    0x00

    0x78
    0x56
    0x34
    0x12
    0x57

    j'ai l'impression que QT lors de la compilation change le type de données de la variable iAdresse_I2C

    Savez-vous comment corriger ce problème ?

    Merci par avance pour votre aide, je suis débutant sur QT.

    Cordialement

  2. #2
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 562
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 562
    Points : 7 628
    Points
    7 628
    Par défaut
    Bonjour,

    Qt n'y est pour rien. Le coupable c'est ton processeur. Comme il est difficile d'en changer, il faut comprendre le problème pour pouvoir le gérer.
    La plupart des processeurs ont des contraintes pour accéder à une données qui dépendent de son type. Par exemple pour ton processeur, un int doit avoir une taille de 4, une adresse multiple de 4 (alignement=4) et stocke en premier l'octet de poids faible puis les autres en finissant par le poids fort (little endian). D'autres processeurs ont des int alignés 2, 4 ou 8, utilisent le big endian(comme les humain en terminant par les unités) ou leur taille fait 2, 4 ou 8 octets.
    Une structure a l'alignement qui est le plus grand alignement de ses composants. Donc ici Memoire et Memoire::iAdresse doivent être à des adresses multiples de 4 et doivent avoir une taille multiple de 4. Pas d'autre solution que de rajouter un trou de 3 octets après iAdresse_i2c et un trou de 2 octets après iDonnees[]. Tu peux vérifier qu'un sizeof(Memoire) donne 63+3+2=68 qui est multiple de 4.
    Le problème est d'imaginer que le buffer à transmettre à un équivalent simple en mémoire.
    Je te propose 2 solutions.
    La première est assez simple à écrire mais pose un énorme problème de compatibilité. Il suffit de déclarer la structure comme étant [[packed]] ou __attribute__((__packed__)) ou #pragma pack(1) ou ... (la syntaxe dépend de ton compilateur pas de Qt), le compilateur va compresser la structure pour y mettre un 'faux' int qui sera composé 4 octets comme un int. Quand le code voudra y écrire ou lire un int, le compilateur produira la code qui fera qu'on semblera y accéder comme un vrai int.
    La seconde est plus complexe et consiste à mieux comprendre qu'un buffer à transmettre n'est pas une zone qui correspond forcément à des variables du langage (remarque que dans la plupart des autres langages ton idée n'aurait aucun équivalent.)

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 627
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 627
    Points : 10 551
    Points
    10 551
    Par défaut
    La première chose à faire, est de réorganiser ses données en fonction du type : les types qui prennent le + d'octets en premier et les plus petits en dernier.

    Dans ton cas (en 32 bits - 4 octets), si tu mets en premier iAdresse, ensuite ton tableau iDonnees[57] et enfin tes 2 autres membres iNb_Octet et iAdresse_I2C, ton bourrage ("padding" en anglais) devrait se produire à la fin de la structure (4 + 57 + 2 + 1 de paddding), au pire après ton tableau et à la fin (4 + 57 + 3 de padding + 2 + 2 de paddding).

    Une autre solution (celle de mon V.D.D., voisin du dessus @dalfab), c'est de créer un tableau de 60, et de le transmettre qu'à partir de la case 3, parce qu'au début tu as mis tes 2 membres (<- cela fait une structure avec des décalages ("offset" en anglais) pour récupérer les bonnes valeurs)

    Un exemple simple (non compilé), si tous tes membres sont de type char :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    typedef enum e_mem_member {
         MEM_MEMBER_BYTE         = 0,
         MEM_MEMBER_I2C_ADDRESS  = 1,
         MEM_MEMBER_END          = 3
    } t_mem_member;
     
     
    typedef struct s_mem {
            unsigned int  address;
            unsigned char data[60];
    } t_mem;
     
     
    void mem_set_member(s_mem* mem, t_mem_member member, char value) {
        if ((mem != NULL) && (member < MEM_MEMBER_END)) {
            *(mem->data + member) = value;
        }
    }

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 631
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 631
    Points : 30 865
    Points
    30 865
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Un autre souci avec ton idée, c'est qu'elle est brillante mais interdite. Une union n'est pas faite à l'origine pour transformer une représentation des données mais juste pour gagner de la place (à l'époque ou la place était rare). Donc si tu es sûr de ne jamais utiliser a et b en même temps, tu as alors possibilité d'inclure a et b dans une union pour que ces deux variables occupent le même espace mémoire. Ensuite tu remplis "a", puis tu traites "a". Puis tu remplis "b", puis tu traites "b". Mais tu n'as pas le droit de remplir "a" puis d'aller regarder ce que ça donne dans "b" car ça donne un UB.

    Donc si tu veux splitter ta structure dans un tableau de char, tout en prenant en compte (en plus) le fait que la norme précise juste qu'un int fait "au minimum" 4 octets (donc il a parfaitement le droit d'en faire plus et j'ai connu une fois un os où il en faisait 6 !!!), il te faut l'écrire de cette façon
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //Structure pour les données mémoire
    struct s_Memoire {
    	unsigned char iAdresse_I2C;
    	unsigned int iAdresse;
    	unsigned char iNb_Octet;
    	unsigned char iDonnees[57];
    } pMemoire;
     
    unsigned char *pDonnees;
    pDonnees=malloc(sizeof(struct sMemoire));
    memcpy(pDonnees, &pMemoire, sizeof(struct sMemoire));
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. problème de l'union
    Par casa88 dans le forum Bases de données
    Réponses: 5
    Dernier message: 19/02/2010, 16h48
  2. Réponses: 15
    Dernier message: 07/11/2008, 16h53
  3. Réponses: 2
    Dernier message: 15/12/2006, 16h19
  4. Problème requête avec UNION et ORDER BY
    Par Yann21 dans le forum Langage SQL
    Réponses: 12
    Dernier message: 12/12/2003, 12h02

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