Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 09/05/2008, à 16:33

darkweaver87

[Résolu] Endianness

Bonjour,

J'ai un petit soucis avec de l'endianness ...

Dans /usr/include/endian.h j'ai un __BYTE_ORDER qui vaut __LITTLE_ENDIAN mais il semblerait que les programmes que je code soit en big ...

J'avoue que je suis un peu dérouté là ...

Ce ne serait pas le compilo qui joue des tours ?

Merci d'avance !

Dernière modification par darkweaver87 (Le 10/05/2008, à 10:00)


Gentoo noyau 2.6.34-r6

Hors ligne

#2 Le 09/05/2008, à 17:10

snapshot

Re : [Résolu] Endianness

Sur les architectures x86, tu es bien en little-endian, contrairement aux architectures 68000 ou PowerPC qui sont en big-endian.

Si tu programmes sous x86 un logiciel pour décoder du JPEG par exemple, ou si tu fais du réseau, ou si tu veux tout simplement un code portable, il te faudra faire des conversions au moyen des macros hton et ntoh (en version short et longue : htons, ntohs, htonl, ntohl) définies dans le fichier <netinet/in.h>


Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !

Hors ligne

#3 Le 09/05/2008, à 17:46

darkweaver87

Re : [Résolu] Endianness

Merci pour votre réponse.

Je connais déjà ces macros.

En fait j'ai un projet de réseau à faire qui est d'implanter de l'IP over UDP (pour plus d'explications cf. http://www.labri.fr/perso/allali/index. … Reseau2008).
Au niveau de la couche IP que j'implante, je récupère les données de la couche ethernet sous forme de char *.

Du coup je lis du big endian.

Voici le code qui s'occupe de lire par exemple, le champ longueur totale :

void set_longueur_totale(ip_paquet ipp, char *data){
  VERIFY_NULL_POINTER(ipp);
  VERIFY_NULL_POINTER(data);
  ENDIANNESS16(ipp->longueur_totale, data[2]<<8 | data[3]);
}

Avec la macro et les fonctions suivantes :

#define ENDIANNESS16(var, number)			\
  if(!is_big_endian_machine()){				\
    var = convert_to_little_endian_uint16_t(number);	\
  }							\
  var = number;
	
int is_big_endian_machine(){
  return (255 & 0x00FF) > 0;
}

uint16_t convert_to_little_endian_uint16_t(uint16_t in)
{
  uint16_t out;
  char *p_in = (char *) &in;
  char *p_out = (char *) &out;
  p_out[0] = p_in[1];
  p_out[1] = p_in[0];
  return out;
}

NB: data suit la RFC 791
Au départ, je me suis dit que j'allais utiliser un truc du style :

ipp->longueur_totale = ntohs(data[2]<<8 | data[3]);

Mon problème c'est que comme je suis déjà en big endian (à cause du network byte order), la macro m'inverse les deux octets alors que je ne veux pas. Par exemple au lieu de me trouver avec une valeur de 0xFF00 je me trouve avec 0x00FF. Et c'est très génant ...

Par ailleurs je ne vois pas comment faire autrement pour lire la trame qu'avec des caractères et masquages et déclages binaires ...

Pour conclure, ce qui me déroute c'est que __BYTE_ORDER vaut __LITTLE_ENDIAN et pourtant ma fonction is_big_endian_machine() qui semble correcte, m'indique que je suis en big endian ...

Si j'ai dû faire cette fonction c'est que le endian.h n'existe pas sous solaris 9 et je ne sais pas comment, de manière très portable, récupérer l'endianness de la machine ...

Je suis un peu paumé et suis ouvert à toute suggestion ...

Merci encore snapshot

Dernière modification par darkweaver87 (Le 09/05/2008, à 17:47)


Gentoo noyau 2.6.34-r6

Hors ligne

#4 Le 09/05/2008, à 20:12

snapshot

Re : [Résolu] Endianness

Oula, oui c'est toujours casse-tête ces conversions...

Plutot que de faire un shift plus un or logique, j'essaierai de passer par un cast :

ipp->longueur_totale = ntohs((uint16_t *) &(data[2])  );

Mais je ne suis vraiment pas sur de la syntaxe, on a vite fait de se planter. En gros, prendre l'adresse de data[2] et la caster en un pointeur sur un entier 16 bits, qui est inversé au besoin pour s'adapter à l'endianness...
Il y a probablement une façon plus jolie de l'écrire (peut être tout simplement data+2)... Il faut faire des essais.


Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !

Hors ligne

#5 Le 09/05/2008, à 20:21

snapshot

Re : [Résolu] Endianness

et pour ta fonction de test, je passerai par une union, plus explicite :
du genre :

union {
  int i;
  char c[sizeof(int)];
} u;
u.i=0xff
return u.c[0];

qui doit retourner 1 si c'est du little endian

Edit:
Qui doit retourner non null si c'est du little endian

Dernière modification par snapshot (Le 09/05/2008, à 21:23)


Pensez à mettre [Résolu] dans le titre une fois votre problème réglé !

Hors ligne

#6 Le 09/05/2008, à 20:41

nicolas.sitbon

Re : [Résolu] Endianness

tu étudies au LABRI?

Hors ligne

#7 Le 09/05/2008, à 21:13

darkweaver87

Re : [Résolu] Endianness

Non je suis étudiant à l'ENSEIRB


Gentoo noyau 2.6.34-r6

Hors ligne

#8 Le 10/05/2008, à 10:00

darkweaver87

Re : [Résolu] Endianness

Merci snapshot !!

Ca marche nickel !

Plus besoin de détecter l'endianness avec le code suivant (tu y étais presque mais bon il était tard ... lol) :

void set_longueur_totale(ip_paquet ipp, char *data){
  VERIFY_NULL_POINTER(ipp);
  VERIFY_NULL_POINTER(data);
  ipp->longueur_totale = ntohs(*((uint16_t *) &(data[2])));
}

Merci encore ...
@+


Gentoo noyau 2.6.34-r6

Hors ligne