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 :

Demande de précision sur les structures : utilisation de memcmp


Sujet :

C

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 840
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 840
    Points : 1 003
    Points
    1 003
    Par défaut Demande de précision sur les structures : utilisation de memcmp
    Bonjour,

    J'ai lu dans la FAQ qu'il ne faut pas utiliser memcmp pour comparer deux strutures :

    J'ai cru comprendre que c'est parce que les espaces mémoires non utilisés entre deux éléments de la structure peuvent avoir n'importe quelle valeur : c'est bien ça ?

    Donc si j'ai la structure suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    typedef struct {
    	u_int8_t a;
    	u_int16_t b;
    	u_int16_t c;
    	u_int8_t d;
    	u_int8_t e;
    } myStruct;
    // size = 8 octets ???
    => Un memcmp() peut potentiellement généré une erreur car entre la variable a et b, il y a un espace vide de 1 octet qui peut avoir n'importe quelle valeur : c'est bien ça ?


    Par contre avec la structure suivante, ça devrait fonctionner quelque soit le compilateur/CPU vu qu'il n'y a plus d'espace libre entre les champs ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    typedef struct {
    	u_int8_t a;
    	u_int8_t d;
    	u_int16_t b;
    	u_int16_t c;
    	u_int8_t e;
    } myStruct;
    // size = 7 octets ???
    => c'est bien ça ?

    merci d'avance

  2. #2
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 486
    Points : 13 696
    Points
    13 696
    Billets dans le blog
    1
    Par défaut
    A mon avis, la réponse est non.

    Je ne connais pas cette entrée de la FAQ mais le problème que tu exposes me semble logique. Les champs des structures peuvent être alignés par le compilateur avec des bits de padding.

    Pour qu'un memcmp entre 2 structures fonctionnent, il faut que tous les champs soient alignés "naturellement" et qu'il n'y ai aucun espace non-controlables.

    Or, la structure suivante ne sera pas forcément alignés sur tous les compilateurs / CPU :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    typedef struct {
    	u_int8_t a;
    	u_int8_t d;
    	u_int16_t b;
    	u_int16_t c;
    	u_int8_t e;
    } myStruct;
    // size = 7 octets ???
    Pour certaines machines 16 bits, le compilateur peut aligner tous les champs sur des int16_t et tu auras des bits de padding entre a et d. Ton memcmp pourrait donc échouer.

    D'ailleurs, si je compile la structure suivante avec MinGW :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    typedef struct {
    	char a;
    	char d;
    	short b;
    	short c;
    	char e;
    } myStruct;
    , j'obtiens un warning de padding :
    d:\...\main.c|24|warning: padding struct size to alignment boundary|
    Il doit y avoir des bits de padding entre e et la fin de la structure car la structure suivante ne pose pas de problème :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    typedef struct {
    	char a;
    	char d;
    	short b;
    	short c;
    	short e;
    } myStruct;

    Un petit sizeof(myStruct) te dit quoi ?

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 840
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 840
    Points : 1 003
    Points
    1 003
    Par défaut
    merci pour ta réponse

    le lien de la FAQ : http://c.developpez.com/faq/index.ph...CT_comparaison

    contrairement a toi je n'ai pas de #warning (compilateur µControlleur PIC32 => 32bits)

    code de test :
    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
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
     
    	typedef struct {
    		UINT8 a;
    		UINT8 d;
    		UINT16 b;
    		UINT16 c;
    		UINT8 e;
    	} myStructA;
    	myStructA valA;
    	printf("sizeof(myStructA) = %li\r\n", sizeof(myStructA));
    	printf("@valA.a = 0\r\n");
    	printf("@valA.d = %li\r\n", (UINT32)&valA.d - (UINT32)&valA.a);
    	printf("@valA.b = %li\r\n", (UINT32)&valA.b - (UINT32)&valA.a);
    	printf("@valA.c = %li\r\n", (UINT32)&valA.c - (UINT32)&valA.a);
    	printf("@valA.e = %li\r\n", (UINT32)&valA.e - (UINT32)&valA.a);
     
    	typedef struct {
    		UINT8 a;
    		UINT8 d;
    		UINT16 b;
    		UINT16 c;
    		UINT16 e;
    	} myStructB;
    	myStructB valB;
    	printf("sizeof(myStructB) = %li\r\n", sizeof(myStructB));
    	printf("@valB.a = 0\r\n");
    	printf("@valB.d = %li\r\n", (UINT32)&valB.d - (UINT32)&valB.a);
    	printf("@valB.b = %li\r\n", (UINT32)&valB.b - (UINT32)&valB.a);
    	printf("@valB.c = %li\r\n", (UINT32)&valB.c - (UINT32)&valB.a);
    	printf("@valB.e = %li\r\n", (UINT32)&valB.e - (UINT32)&valB.a);
     
     
    	typedef struct {
    		UINT8 a;
    		UINT8 d;
    		UINT16 b;
    		UINT32 c;
    		UINT16 e;
    	} myStructC;
    	myStructC valC;
    	printf("sizeof(myStructC) = %li\r\n", sizeof(myStructC));
    	printf("@valC.a = 0\r\n");
    	printf("@valC.d = %li\r\n", (UINT32)&valC.d - (UINT32)&valC.a);
    	printf("@valC.b = %li\r\n", (UINT32)&valC.b - (UINT32)&valC.a);
    	printf("@valC.c = %li\r\n", (UINT32)&valC.c - (UINT32)&valC.a);
    	printf("@valC.e = %li\r\n", (UINT32)&valC.e - (UINT32)&valC.a);
     
    	typedef struct {
    		UINT8 a;
    		UINT8 b;
    		UINT8 c;
    	} myStructD;
    	myStructD valD;
    	printf("sizeof(myStructD) = %li\r\n", sizeof(myStructD));
    	printf("@valD.a = 0\r\n");
    	printf("@valD.b = %li\r\n", (UINT32)&valD.b - (UINT32)&valD.a);
    	printf("@valD.c = %li\r\n", (UINT32)&valD.c - (UINT32)&valD.a);
    affichage :
    sizeof(myStructA) = 8
    @valA.a = 0
    @valA.d = 1
    @valA.b = 2
    @valA.c = 4
    @valA.e = 6
    sizeof(myStructB) = 8
    @valB.a = 0
    @valB.d = 1
    @valB.b = 2
    @valB.c = 4
    @valB.e = 6
    sizeof(myStructC) = 12
    @valC.a = 0
    @valC.d = 1
    @valC.b = 2
    @valC.c = 4
    @valC.e = 8
    sizeof(myStructD) = 3
    @valD.a = 0
    @valD.b = 1
    @valD.c = 2
    Donc a priori, les règles pour la définition des structures sont :
    1- les champs sont rangés dans l'ordre de leur déclaration
    2- les champs sont placés à une adresse qui est divisible par leur taille
    3- a la fin de la structure, il y a des octets de padding de façon à ce que la taille de la structure soit divisible par la taille du champs le plus grand déclaré dans la structure
    => reste a savoir si c'est vrai pour n'importe quel compilo/CPU...


    ------------------------
    Citation Envoyé par Bktero
    Pour certaines machines 16 bits, le compilateur peut aligner tous les champs sur des int16_t et tu auras des bits de padding entre a et d. Ton memcmp pourrait donc échouer.
    Tu en es vraiment sure (c'est le cas même pour des char ?) ?
    => ça voudrait donc dire que la liste de règles que j'ai cité précédemment n'est pas bonne pour tout les systèmes (dure dure de faire du code portable T_T )

    -----------------------
    Il y a un moyen alors de faire une comparaison de structure portable qui ne nécessite pas de changer le code en cas de modification des éléments de la structure ?

  4. #4
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Les règles 2 et 3 n'en sont pas : rien ne les garantit.
    La règle 1 est bonne et on peut ajouter qu'il n'y a pas de "trou" avant le premier champ.

    A noter que les questions d'alignement peuvent parfois dépendre des options de compilation pour un compilateur donné.

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 840
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 840
    Points : 1 003
    Points
    1 003
    Par défaut
    ok merci pour les informations.

    Donc un code portable et performant est impossible a développer en C (il faut choisir entre les deux), non ?

    Vous connaissez de bon tuto qui traite du sujet de la portabilité en c (en gros, que faut-il faire pour que le code soit le plus portable possible tout en restant le performant et lors de migration de pouvoir rapidement identifier dans le code les partie qui dépendent du compilo/hardware) ?

  6. #6
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 486
    Points : 13 696
    Points
    13 696
    Billets dans le blog
    1
    Par défaut
    Tu en es vraiment sure (c'est le cas même pour des char ?) ?
    => ça voudrait donc dire que la liste de règles que j'ai cité précédemment n'est pas bonne pour tout les systèmes (dure dure de faire du code portable T_T )
    Sûr et certain.

    J'ai eu le cas au boulot pas plus tard que hier. Au boulot, j'ai un outil de diagnostic qui sert à lire des données en RAM d'un µC. J'ai deux produits équivalent à tester, les possédant en RAM la même structure (avec un paquet de int16_t, un tableau de char, etc.). Je voulais accéder à un champ de la structure connaissant l'adresse de la structure.

    L'un des µC est un 16 bits. Les champs étaient alignés sur une taille de 16 bits et donc mon champ était 22 octets après le début de la structure.

    L'autre est un 32 bits. Tous les int16_t étaient alignés sur des int32_t et le champ auquel je souhaitais accéder étaient 28 octets plus loin.

    contrairement a toi je n'ai pas de #warning (compilateur µControlleur PIC32 => 32bits)
    J'utilise MPLAB avec le compilateur C18 à la maison en ce moment. On ne peut pas dire que les messages de ce compilateur soient géniaux. Possible que la structure soit correctement alignée ; possible qu'il ne te dise rien. Pour C18 (mais je ne sais pas pour les PIC32), il y a 3 niveaux de messages : errors, warnings, messages. Regarde que tout est bien activé. Regarde si tu ne peux pas activer des warnings supplémentaires.


    ok merci pour les informations.

    Donc un code portable et performant est impossible a développer en C (il faut choisir entre les deux), non ?

    Vous connaissez de bon tuto qui traite du sujet de la portabilité en c (en gros, que faut-il faire pour que le code soit le plus portable possible tout en restant le performant et lors de migration de pouvoir rapidement identifier dans le code les partie qui dépendent du compilo/hardware) ?
    De rien

    En assembleur, ce sera encore moins portable et encore plus difficile à maintenir, qu'en penses-tu ?

    La portabilité est une question assez délicate. Sur PC, on peut encore s'en sortir, car on n'est pas à quelques octets près, les architectures sont plus homogènes, on possède des macros permettant de connaitre l'OS pour lequel la compilation est faite (voir ici).

    Sur µC, c'est beaucoup plus compliqué. Les architectures sont très hétérogènes (sauf à rester sur une même famille, éventuellement une même marque). Tout peut changer entre 2 µC :
    • les noms des registres
    • les bits de configuration d'une fonction
    • la manière d'utiliser un périphérique
    • le pinout
    • ...

    Après, la structure dont je t'ai parlé plus haut est portable. Elle compile sans problème sur les 2 µC, pourtant de tailles et de marques différentes. Sauf que dans un cas, elle prend plus de place que dans l'autre.

    A mon avis, faire un code complètement portable d'un µC à l'autre est impossible, ou alors tellement compliqué que tu as plus vite de faire un code facilement adaptable que tu pourras réutiliser moyennant quelques modifications.

  7. #7
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Points : 28 129
    Points
    28 129
    Par défaut
    Citation Envoyé par boboss123 Voir le message
    Donc un code portable et performant est impossible a développer en C (il faut choisir entre les deux), non ?
    Je ne vois pas pourquoi tu dis ca : rien ne t'empeche de definir tes structures comme tu l'entends, et de comparer les champs un a un. Cela sera peut-etre un poil plus lent que le memcmp, mais je ne pense pas que ca soit significatif, sauf dans certains cas particuliers.

    Ne pas oublier avant de chercher a optimiser que l'on passe 80% du temps d'execution dans 20% du code.
    Donc optimiser la phase de demarrage (par exemple) pour reduire le temps d'initialisation alors qu'on ne passe qu'une fois dedans, ce n'est pas forcement une bonne idee.

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 840
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 840
    Points : 1 003
    Points
    1 003
    Par défaut
    ok merci pour les infos

    J'utilise MPLAB avec le compilateur C18 à la maison en ce moment. On ne peut pas dire que les messages de ce compilateur soient géniaux. Possible que la structure soit correctement alignée ; possible qu'il ne te dise rien. Pour C18 (mais je ne sais pas pour les PIC32), il y a 3 niveaux de messages : errors, warnings, messages. Regarde que tout est bien activé. Regarde si tu ne peux pas activer des warnings supplémentaires.
    => j'ai bien les warning qui sont affichés
    => avant j’étais aussi sur PIC18 : une fois que tu passes sur la souplesse de l'environnement PIC32 difficile de revenir en arrière (erreur beaucoup plus explicites avec le compilo, plus de pagination de la mémoire, plus besoin de se casser la tête pour optimiser la taille de la RAM/ROM)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Demande de précisions sur les niveau de visibilité
    Par rbello dans le forum Langage
    Réponses: 6
    Dernier message: 17/09/2007, 00h32
  2. [Jboss][EJB]Demande de confirmation sur la structure.
    Par swirtel dans le forum Wildfly/JBoss
    Réponses: 2
    Dernier message: 17/02/2005, 13h30
  3. Précisions sur les recordset DAO
    Par Igricheff dans le forum VBA Access
    Réponses: 2
    Dernier message: 18/01/2005, 18h16
  4. Précision sur les sauvegarde à chaud
    Par alxkid dans le forum Administration
    Réponses: 2
    Dernier message: 09/08/2004, 19h55
  5. [VBA-E]Demande de précision sur les menus
    Par geffdenimes dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 25/06/2003, 11h46

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