Déterminer l'endianness du système?

Version imprimable

Voir 40 message(s) de cette discussion en une page
Page 1 sur 2 12 DernièreDernière
Citation:


Problème de [codeur de ]compilateur, pas de codeur d'application.
  • 25/07/2006, 22h23
    Pragmateek
    Et c'est portable?
    Si "unsigned long" fait plus de 4 byte?

    Code:

    1
    2
    3
    for(unsigned i=sizeof(long)-1;i>=0;i--){
    buf[12 + (sizeof(long)-1)+i] = (data >> (8 * i)) & 0xFF;
    }

    ?
  • 25/07/2006, 22h33
    Emmanuel Delahaye
    Citation:

    Envoyé par seriousme
    Et c'est portable ?

    Ben oui.
    Citation:

    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.
  • 25/07/2006, 22h42
    Pragmateek
    Il faut juste veiller à ne pas utiliser de données trop grande qui pourrait tenir sur un "long" de 8 byte par exemple?
  • 25/07/2006, 22h55
    Emmanuel Delahaye
    Citation:

    Envoyé par seriousme
    Il faut juste veiller à ne pas utiliser de données trop grande qui pourrait tenir sur un "long" de 8 byte par exemple?

    Encore une fois, les données réseau sont spécifiées. Tu ouvres une RFC, y'a pas de mystères.

    Après, oui, il faut avoir un cerveau en état de marche et connaitre par coeur les tailles minimales garanties de chaque types C et utiliser le bon. Penser aussi à être en unsigned pour éviter les embrouilles.

    Un long de 8 bytes, c'est pas portable (et un byte, c'est quoi tu veux dire 8 x 8 = 64 bits ?).

    Un unsigned long long, c'est OK : 64 bits minimum.
  • 25/07/2006, 23h03
    Pragmateek
    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.
    Il serait plus logique que les normes réseaux surdimensionnent la taille des différents types pour tous les accepter; ce qui risquerait bien sûr d'augmenter souvent inutilement la quantité de byte à transmettre.
  • 25/07/2006, 23h18
    David.Schris
    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:

    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...
  • 26/07/2006, 09h16
    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...

    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...
  • 26/07/2006, 10h47
    David.Schris
    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:

    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 :D
  • 26/07/2006, 10h54
    Médinoc
    Oui, mais c'est plus long.
    Généralement, je suis plutôt pour une structure avec des tailles de champs et de bourrage bien définies (types spécifiant la taille genre uint32_t, pragma pack/attribute packed, etc). Et une sauvegarde en gros de la structure.
  • 26/07/2006, 18h44
    Pragmateek
    Citation:

    A quoi ça sert ?
    Justement puisque les transmission réseaux sont en big endian:
    Code:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    if(BIG_ENDIAN){
    /*transmission sans transformation des donnees*/
    }
    else{
    /*formatage des donnees*/
    /* 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*/
    }

    Et donc gain de temps si l'architecture est déjà big endian.
    Non?:mrgreen:
  • 26/07/2006, 18h56
    Emmanuel Delahaye
    Citation:

    Envoyé par seriousme
    Justement puisque les transmission réseaux sont en big endian:
    Code:

    1
    2
    if(BIG_ENDIAN){
    /*transmission sans transformation des donnees*/


    Ah bon ? En big endian, on ne met pas les données dans le buffer d'émission ?
    Citation:

    Code:

    1
    2
    3
     
    }
    else{


  • 26/07/2006, 19h03
    Pragmateek
    Citation:

    Ah bon ? En big endian, on ne met pas les données dans le buffer d'émission ?
    Oui mais directement, pas en quatre étapes et surtout sans utiliser les opérateurs bit à bit qui sont couteux:
    Code:

    snprintf(buf+12,4,"%ld",data);
    .
  • 26/07/2006, 19h28
    Emmanuel Delahaye
    Citation:

    Envoyé par seriousme
    Oui mais directement, pas en quatre étapes et surtout sans utiliser les opérateurs bit à bit qui sont couteux:
    Code:

    snprintf(buf+12,4,"%ld",data);
    .

    Rien à voir. On parlait de transferts binaires, pas de conversion en chaine (qui est insensible à l'endianness).
  • Voir 40 message(s) de cette discussion en une page
    Page 1 sur 2 12 DernièreDernière