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 :

Déterminer l'endianness du système?


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut Déterminer l'endianness du système?
    Salut!

    Serait il possible avec un code C de déterminer l'endianness du système?
    Si oui est-ce que celui-ci le pourrait:

    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
    #ifndef ERROR
    enum{ERROR=-1,
    #else
    #error ERROR is already defined
    #endif
    LITTLE_ENDIAN,
    BIG_ENDIAN,
    };
     
     
    static int endianness(void){
     
           unsigned char* p_c=calloc(sizeof(int),1);
     
           if(p_c==NULL){
                         return ERROR;
                         }
     
           p_c[0]=0xFFFF;
     
           int* p_i=(int*)p_c;
     
           return *p_i==255?LITTLE_ENDIAN:BIG_ENDIAN;
     
    }
    ?

    Sinon existe il une constante définie par GCC qui l'indique?

    Merci.

  2. #2
    Membre émérite

    Profil pro
    Inscrit en
    Août 2003
    Messages
    878
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 878
    Par défaut
    Il est où le free() ?

    En attendant ta réponse :
    Citation Envoyé par comp.lang.c FAQ list · Question 20.9
    Q: How can I determine whether a machine's byte order is big-endian or little-endian?

    A: The usual techniques are to use a pointer:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	int x = 1;
    	if(*(char *)&x == 1)
    		printf("little-endian\n");
    	else	printf("big-endian\n");
    or a union:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    	union {
    		int i;
    		char c[sizeof(int)];
    	} x;
    	x.i = 1;
    	if(x.c[0] == 1)
    		printf("little-endian\n");
    	else	printf("big-endian\n");

  3. #3
    Membre éprouvé
    Avatar de granquet
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    1 201
    Détails du profil
    Informations personnelles :
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 201
    Par défaut
    je pense que c'est possible ... qu'il y'as de l'idée ...
    mais j'ai l'impression que le code est faux.

    --

    haben reponse de David avec corrections
    j'aime bien la methode de l'union, je la trouve elegante.

  4. #4
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par seriousme
    Serait il possible avec un code C de déterminer l'endianness du système?
    A quoi ça sert ?

    Ca fait 15 ans que j'écris du code portable (x86/68k/PPC) sans jamais me préoccuper de ce détail.

    La seule fois où je l'ai fait c'est pour m'apercevoir que c'était inutile et le code était faux.

  5. #5
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Il est où le free() ?
    Pour 4 byte... mais c'est vrai que pour le principe:

    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
    static int endianness(void){
     
           unsigned char* p_c=calloc(sizeof(int),1);
     
           if(p_c==NULL){
                         return ERROR;
                         }
     
           p_c[0]=0xFFFF;
     
           int* p_i=(int*)p_c;
     
           int n=*p_i;
     
           free(p_c);
     
           return n==255?LITTLE_ENDIAN:BIG_ENDIAN;
     
    }
    Et existe il une constante dans un header de GCC qui l'indiquerait?

  6. #6
    Membre émérite

    Profil pro
    Inscrit en
    Août 2003
    Messages
    878
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 878
    Par défaut
    Citation Envoyé par seriousme
    Pour 4 byte... mais c'est vrai que pour le principe:
    Non, ce n'est pas juste "pour le principe" : c'est pour prendre une bonne habitude. Si tu prends l'habitude de toujours libérer la mémoire que tu réserves, tu n'oublieras jamais de le faire (oui, je sais, cela semble assez évident)...ça peut sauver des vies...

    Citation Envoyé par seriousme
    Et existe il une constante dans un header de GCC qui l'indiquerait?
    Je ne sais pas ce que tu appelles un "header de gcc".
    Par contre, chez moi (et chez pas mal d'autres), "ctype.h" inclue <endian.h> qui définit "__LITTLE_ENDIAN", "__BIG_ENDIAN", "__PDP_ENDIAN" (sans "__" sous BSD) et inclue <bits/endian.h> qui définit "__BYTE_ORDER" pour ma plateforme.
    Donc, je pourrai faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <endian.h>
    #if __BYTE_ORDER == __LITTLE_ENDIAN
    /* blabla */
    #elif __BYTE_ORDER == __BIG_ENDIAN
    /* bleble */
    #else
    /* blibli */
    #endif
    ...ce qui nous montre que tu n'as pas dû chercher dans tes "headers" avant de demander...
    (et puis, niveau portabilité, j'ai un doute...quelqu'un confirme ?)

    Sinon, concernant le reste de ton code :
    • "enum { /* blabla */ };" ==> là, c'est personnel, je n'aime pas les "enum" tous seuls, je préfère les "typedef enum { /* blabla */ } t_UnNomParlant;" car (en relisant mon code) ma fonction ne retournera pas juste un "int" anonyme et car les noms donnés aux valeurs pourront plus facilement être identifiés (en regardant le type de la variable à laquelle je les affecte) ;
    • "LITTLE_ENDIAN, BIG_ENDIAN, }" ==> elle sert à quoi la virgule à la fin ?
    • "if(p_c==NULL){" ==> quelques espaces ne feraient pas de mal ("if ( p_c == NULL ) {") ;
    • "p_c[0]=0xFFFF;" ==> "warning: large integer implicitly truncated to unsigned type" ;
    • "int* p_i=(int*)p_c;" ==> "parse error before `int'" (déclarations ==> en début de bloc !!! Sinon, fais du VB) ;
    • "return *p_i==255?LITTLE_ENDIAN:BIG_ENDIAN;" ==> "`p_i' undeclared" (cf. ci-dessus) ;
    • le déjà mentionné free() manquant (et le calloc inutile car, comme tu dis, "pour 4 bytes"...).



    Citation Envoyé par Emmanuel Delahaye
    Problème de [codeur de ]compilateur, pas de codeur.
    Sauf que tout le monde n'est pas "codeur de compilateur" donc si il y a "problème", c'est le codeur (pas "de compilateur") qui devra le régler.
    Un petit exemple... Prends un bout de code de la librairie OpenSSL comme http://cvs.openssl.org/getfile/opens...5-ia64.S?v=1.3 (pris au hasard). Tu y trouveras par exemple des "#ifdef HOST_IS_BIG_ENDIAN". Ne me dis pas "ce n'est pas du C, c'est de l'assembleur" car tu ne feras qu'abonder dans mon sens (enfin...en partie) : si c'est codé en assembleur, c'est bien parce-que ce n'était pas qu'un problème de compilateur (ou en tous cas que le "problème" n'est pas résolu). Tu vois où je veux/voulais en venir ?
    Mais, à part en crypto (avec des besoins en termes de performance), j'ai rarement vu, et là c'est moi qui vais dans ton sens, de réel besoin de tester l'indianité...encore moins en C.

    Citation Envoyé par seriousme
    Si sur une implémentation un type fait "n" byte et que ce même type sur le réseau doit tenir sur "m"<"n" byte il faut bricoler pour le transmettre.
    Tu dis "ce même type", c'est là que tu te crées un problème où il n'y en a pas : cela ne doit pas être vu comme un "même type" (d'un côté c'est du C sur une architecture donnée, de l'autre c'est un protocole (commun à plusieurs architectures)).
    Autrement dit, et comme l'a écrit Emmanuel, le problème (pour le codeur) est seulement de "connaitre par coeur les tailles minimales garanties de chaque types C et utiliser le bon" en fonction du protocole. Le problème pour celui qui définit le protocole est de bien choisir les tailles de données à transmettre sans se fixer sur une architecture mais en se basant sur les besoins de ce qu'il y a à transmettre. Quand ces besoins peuvent changer, il y a moyen de définir (dans le protocole) des types "à taille variable" (exemple classique : transmettre une chaine en unicode) ou de transmettre la version du protocole utilisé pour pouvoir le faire évoluer.
    Je ne sais pas si j'ai été très clair...

  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
    Connaitre (dynamiquement ou non) l'endianness d'un système, ça peut être utile dès que tu veux sauvegarder des fichiers binaires et que tu n'as pas envie de dépendre de la bibliothèque où se trouvent les htons/ntohs/htonl/ntohl...

    Sous Windows, on dépend de wsock32.lib+dll ou de ws2_32.lib+dll, et je ne sais même pas si on a besoin ou non d'un appel à WSAStartup() pour les utiliser. Si c'est le cas, faire ses propres fonctions peut s'avérer un gain de maintenabilité du code...

    Edit: Je viens de tester, le WSAStartup() est inutile, il suffit d'être lié à la bibliothèque pour avoir accès à ces fonctions. Ainsi, connaitre l'endianness n'a que peu d'importance...
    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 émérite

    Profil pro
    Inscrit en
    Août 2003
    Messages
    878
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 878
    Par défaut
    Citation Envoyé par Médinoc
    Connaitre (dynamiquement ou non) l'endianness d'un système, ça peut être utile dès que tu veux sauvegarder des fichiers binaires et que tu n'as pas envie de dépendre de la bibliothèque où se trouvent les htons/ntohs/htonl/ntohl...
    Vois le bout de code d'Emmanuel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
       unsigned char buf[123] = {0};
       unsigned long data = 0x1234;
     
       /* offset arbitraire */
       buf[12 + 0] = (data >> (8 * 3)) & 0xFF; /* MSB  = 00 */
       buf[12 + 1] = (data >> (8 * 2)) & 0xFF; /*         = 00 */
       buf[12 + 2] = (data >> (8 * 1)) & 0xFF; /*         = 12 */
       buf[12 + 3] = (data >> (8 * 0)) & 0xFF; /* LSB   = 34*/
    Il ne dépend d'aucune bibliothèque

  9. #9
    Membre émérite

    Profil pro
    Inscrit en
    Août 2003
    Messages
    878
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 878
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    A quoi ça sert ?
    Je tente ma chance :
    • pour transmettre des données via un réseau d'une machine x86 à une machine 68k (ou l'inverse) en étant sûr qu'il n'y ait pas de "mélange" ? [1]
    • pour optimiser du code au mieux pour chaque type d'architecture ?


    Une question que je me pose quand même : à quoi ça sert à l'exécution ?
    Cela me semblerait plus propre de tester ça avant la compilation (ex. : avec la macro AC_C_BIGENDIAN d'autoconf).

    [1] - quoiqu'avec htons()/htonl() & Co....

  10. #10
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par David.Schris
    Je tente ma chance :
    • pour transmettre des données via un réseau d'une machine x86 à une machine 68k (ou l'inverse) en étant sûr qu'il n'y ait pas de "mélange" ? [1]
    • Ben il suffit de respecter les conventions du réseau (MSB en tête) et de travailler byte par byte :

      Emission d'un mot de 32 bits :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
       
         unsigned char buf[123] = {0};
         unsigned long data = 0x1234;
       
         /* offset arbitraire */
         buf[12 + 0] = (data >> (8 * 3)) & 0xFF; /* MSB  = 00 */
         buf[12 + 1] = (data >> (8 * 2)) & 0xFF; /*         = 00 */
         buf[12 + 2] = (data >> (8 * 1)) & 0xFF; /*         = 12 */
         buf[12 + 3] = (data >> (8 * 0)) & 0xFF; /* LSB   = 34*/
       
         emettre (buf, sizeof buf);
      Ce code est indépendant de l'architecture.
    • pour optimiser du code au mieux pour chaque type d'architecture ?
  11. Problème de [codeur de ]compilateur, pas de codeur d'application.

  • #11
    Membre Expert
    Avatar de Pragmateek
    Homme Profil pro
    Formateur expert .Net/C#
    Inscrit en
    Mars 2006
    Messages
    2 635
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Formateur expert .Net/C#
    Secteur : Conseil

    Informations forums :
    Inscription : Mars 2006
    Messages : 2 635
    Par défaut
    Et c'est portable?
    Si "unsigned long" fait plus de 4 byte?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for(unsigned i=sizeof(long)-1;i>=0;i--){
    buf[12 + (sizeof(long)-1)+i] = (data >> (8 * i)) & 0xFF;
    }
    ?

  • #12
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par seriousme
    Et c'est portable ?
    Ben oui.
    Si "unsigned long" fait plus de 4 byte?
    On s'en fiche. Les poids forts > 32 bits sont ignorés. C'est toi qui a fait une boucle vaseuse, pas moi.

    Les formats des données réseau sont spécifiées. C'est pas comme en C où les tailles des types sont variables. Si la données fait 32 bits, c'est 4 octets. Point. Evidemment, en C, pour être portable on prend le type de taille >= qui va bien. (ici, unsigned long)

    Il faut décoreller dans sa tête le format réseau qui est indépendant de l'architecture et du langage, de l'implémentation.

  • + Répondre à la discussion
    Cette discussion est résolue.
    ActualitésFAQ CTutoriels CLivres CCompilateurs et outils CSources CGTK+

    Discussions similaires

    1. Déterminer les coordonnées 3D d'un système stéréo
      Par wheelskad dans le forum OpenCV
      Réponses: 25
      Dernier message: 13/05/2012, 21h56
    2. Déterminer version 32/64 bits du système d'exploitation
      Par Maxiglider dans le forum Langage
      Réponses: 10
      Dernier message: 14/02/2011, 15h11
    3. Déterminer l'emplacement des dossiers systèmes
      Par soso78 dans le forum Windows Forms
      Réponses: 3
      Dernier message: 04/01/2008, 10h33
    4. Réponses: 2
      Dernier message: 16/05/2007, 19h26
    5. [Système] Déterminer l'état d'un process
      Par 501darts dans le forum Langage
      Réponses: 1
      Dernier message: 30/01/2007, 18h59

    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