[C] conversion fichier binaire Big-Little Endian [RESOLU]

conversion fichier binaire Big-Little Endian [RESOLU] [C] - C - Programmation

Marsh Posté le 30-07-2008 à 15:56:50    

Bonjour, je suis face à un petit problème.
 
J'ai un fichier binaire dont je change l'endianness octet par octet.
J'obtiens alors un deuxième fichier binaire.
En ouvrant ces deux fichiers avec un éditeur hexadécimal et en comparant quelques valeurs, j'ai vérifié que ma conversion était bonne.
Par exemple à l'adresse 0x000C426C du premier fichier, je trouve la valeur hexa 1C
à la même adresse dans l'autre fichier je trouve la valeur hexa 38.
1C(hexa)=00011100(binaire) et 38(hexa)=00111000(binaire)
donc la conversion est OK.
 
Ensuite j'utilise un autre prog (que je n'ai pas codé) qui me décode le fichier binaire en txt pour pouvoir le lire.
J'ai compilé cet outil de décodage sur PC et sur Station Sun.
Sur PC, pas de prob, tout s'affiche bien.
Par contre sur Sun, ça merde.
 
Pensez-vous que ça vient du truc de décodage, ou bien ma "preuve" convernant ma conversion sur les fichiers binaires ne suffit pas, et c'est dans mes binaires que ça merde ?
 
merci


Message édité par Facewindu le 06-08-2008 à 17:53:12
Reply

Marsh Posté le 30-07-2008 à 15:56:50   

Reply

Marsh Posté le 30-07-2008 à 16:22:04    

La boutitude ca concerne generalement(1) l'ordre des bytes dans des mots, pas l'ordre des bits dans des bytes.
 
(1) Du moins tel que vue par les programmeurs; si on fait des transmission bit par bit, il faut aussi s'occuper de l'ordre des bits dans les bytes; et rien ne garanti que ce sera le meme que l'ordre des bytes dans des mots.

Reply

Marsh Posté le 31-07-2008 à 12:57:48    

Oui, tu as surement raison, faut que j'intervertisse mes Bytes et pas mes bits dans les Bytes.
Du coup ça me soulève un autre problème :
Les types de données stockées dans mon fichier binaire dépendent de plusieurs trucs, du coup ça me fait plein de cas à traiter.
Par exemple :
cas 1 : uint32, uint8, uint8
cas 2 : uint16, uint64, etc etc
(et j'ai pas mal de cas, genre une trentaine)
 
Comme ça là maintenant je vois qu'un seul moyen, c'est de faire un truc du genre :
dans le cas 1, tu prends les 4 premiers Bytes et tu les switches, puis le Byte suivant et tu le switches, etc etc
dans le cas 2, tu prends les 2 premiers, puis les 8 suivants, etc etc
 
Ca va être chiant de me taper tous les cas un par un.
Existe-til une méthode pour parcourir la mémoire Byte par Byte et savoir quand le Byte suivant appartient à une autre variable ?


Message édité par Facewindu le 31-07-2008 à 12:59:11
Reply

Marsh Posté le 31-07-2008 à 13:05:02    

tu pourrais pas gruger et utiliser htons et ntohs à des fin détournés.
Sinon, t'as accés à la structure que tu lit/ecrit ? Si oui le mieux et de faire une fonction qui prend une instance de cette structure et le boutise avant de la sauver et vice et versa

Reply

Marsh Posté le 31-07-2008 à 13:36:44    

oui j'ai accès à la structure (j'ai un pointeur sur le début de la structure et je connais normalement son type (un de mes cas) et son taille en Bytes.
Imaginons que je crée une fonction qui la prenne en instance, en quoi ça change par rapport à ce que j'ai expliqué avant ?
Comment je peux lui dire de boutiser chaque variable de la structure ?

Reply

Marsh Posté le 31-07-2008 à 13:48:46    

D'apres ce que je comprends, la suggestion de Joel est ton traitement des cas.  Et je ne connais pas d'autres methodes.

Reply

Marsh Posté le 31-07-2008 à 14:01:35    

ouais, bah je vais mettre les mains dans le camboui. Ca va être long et moche mais bon ...
J'avais aussi penser à faire une méthode très généraliste qui boutise une variable de n'importe quelle type, en mettant des void* et des typeof dedans, mais je me suis cassé les dents.

Reply

Marsh Posté le 31-07-2008 à 14:25:00    

tu dois rester en C ? Car je me demande si dans boost::serialization t'as ça qui est tout géré de base

Reply

Marsh Posté le 31-07-2008 à 14:37:32    

et oui, je dois rester en C :(
je vous tiens au courant (surement demain, voire lundi quand j'aurais fini) pour dire si ça marche.


Message édité par Facewindu le 31-07-2008 à 14:38:05
Reply

Marsh Posté le 01-08-2008 à 13:47:39    

Du nouveau.
En fait, le mec qui a codé le premier fichier binaire a utilisé __atribute__((packed)) pour limiter la taille mémoire.
Du coup peut-être que vous pouvez m'indiquer si y a moyen de "unpacker" tout ça, histoire d'avoir mes variables qui sont pas à cheval sur des Bytes ?

Reply

Marsh Posté le 01-08-2008 à 13:47:39   

Reply

Marsh Posté le 01-08-2008 à 13:57:23    

si tu utilise aussi le même attribut pour tes structures ca devrait passer. Ensuite à toi de remettre tes données dans une structure non-packed

Reply

Marsh Posté le 01-08-2008 à 16:09:43    

Juste pour ma culture (et désolé de pourrir le topic si c'est le cas) à quoi ça sert aujourd'hui d'utiliser encore le big endian ?
 
De mémoire de mes cours de système, le big endian a été inventé par intel je crois, afin d'optimiser le traîtement des grands nombres sur les processeurs 8 bits :
 
si on additionne deux entiers de 32 bits avec un processeur 8 bits, on est emmerdé car on doit commencer par le 4° byte, garder la retenue, passer au 3°, puis au 2° et enfin au 1°.
 
alors qu'en big endian, le byte "des unités" étant en premier, on fait le calcul dans l'odre des bytes en mémoire, ce qui est bien plus pratique.
 
mais maintenant que tous les processeurs sont 32 ou 64 bits, à quoi que sert d'avoir encore cette représentation puisque le processeur n'y gagne rien, au contraire, il doit remettre les bytes dans l'ordre avant de faire le calcul (enfin, du moins je suppose qu'il est câblé pour savoir faire le calcul directement en big endian en plus du sens normal du traîtement)... elle est encore beaucoup utilisée ?
 
et n'existe-t-il pas une variante pour les processeurs 32 bits qui manipulent des nombres de 64 ou 128 bits ? (c'est à dire non plus inverser les bytes, mais des paquets de 4 bytes)

Message cité 1 fois
Message édité par MagicBuzz le 01-08-2008 à 16:12:33
Reply

Marsh Posté le 01-08-2008 à 16:10:58    

... c'est câblé point barre, jamais t'as besoin de te savoir ce qui se passe. Maintenant, ok, on arrête de faire du BE et du LE ...
Qui se tape tout les patchs pour un demi-milliard d'applications LE ou BE qui doivent lire des binaires natifs ?


Message édité par Joel F le 01-08-2008 à 16:11:32
Reply

Marsh Posté le 01-08-2008 à 16:15:02    

nan mais je ne parle pas d'arrêter le support sur les processeurs :o (pourquoi tu veux systématiquement déformer mes propos pour me voler dans les plumes ?)
 
ma question est : aujourd'hui, à quoi ça sert, si à l'origine ça servait vraiment à ce que j'ai retenu de mes cours ?
 
et est-ce encore utilisé sur les compilateurs modernes (faits pour processeurs 32 ou 64 bits)
 
biensûr qu'il faut rester compatible, mais ma question n'a rien à voir avec la compatibilité, juste savoir s'il y a une utilité


Message édité par MagicBuzz le 01-08-2008 à 16:15:49
Reply

Marsh Posté le 01-08-2008 à 16:19:27    

ça n'a rien avoir avec le compilateur :E c'est le processeur qui est comme ça c'est tout :E

 

Wiki a un bon exemple :

Citation :


Les nombres big-endian sont plus faciles à lire lorsqu'on débogue un programme car leur contenu est directement lisible sans avoir à changer l'ordre des octets constituant le nombre. Cela est dû au fait que l'ordre des chiffres est le même que celui de l'écriture normale.

 

Le mode little-endian présentait des avantages lorsque les processeurs utilisaient des tailles de registre variables, c’est-à-dire 8, 16 ou 32 bits. À partir d'une adresse mémoire donnée, on pouvait lire le même nombre en lisant 8, 16 ou 32 bits. Par exemple, le nombre 33 (0x21 en hexadécimal) s'écrit 21 00 00 00 en little endian en 32 bits, ce qui se lit toujours 21 quel que soit le nombre d'octets lus. Ceci est faux en big-endian car la première adresse change suivant le nombre d'octets à lire.

 

Y a pas d'avantage ou de désavantage inhérent, donc on fait ce qui nous arrange au moment de concevoir le proc et c'est tout.


Message édité par Joel F le 01-08-2008 à 16:21:15
Reply

Marsh Posté le 01-08-2008 à 16:27:46    

ok.
donc j'avais mal compris mon cours. je croyais que c'était le programme qui gérait ça. mais non, c'est le processeur :jap: donc du coup, effectivement la question de l'utilité ne se pose même pas, au risque de se manger un cuisant échec commercial comme Intel et son I64 en voulant tout remettre à plat la structure de son proc


Message édité par MagicBuzz le 01-08-2008 à 16:28:42
Reply

Marsh Posté le 01-08-2008 à 16:59:05    

MagicBuzz a écrit :

Juste pour ma culture (et désolé de pourrir le topic si c'est le cas) à quoi ça sert aujourd'hui d'utiliser encore le big endian ?
 
De mémoire de mes cours de système, le big endian a été inventé par intel je crois, afin d'optimiser le traîtement des grands nombres sur les processeurs 8 bits :
 
si on additionne deux entiers de 32 bits avec un processeur 8 bits, on est emmerdé car on doit commencer par le 4° byte, garder la retenue, passer au 3°, puis au 2° et enfin au 1°.
 
alors qu'en big endian, le byte "des unités" étant en premier, on fait le calcul dans l'odre des bytes en mémoire, ce qui est bien plus pratique.
 
mais maintenant que tous les processeurs sont 32 ou 64 bits, à quoi que sert d'avoir encore cette représentation puisque le processeur n'y gagne rien, au contraire, il doit remettre les bytes dans l'ordre avant de faire le calcul (enfin, du moins je suppose qu'il est câblé pour savoir faire le calcul directement en big endian en plus du sens normal du traîtement)... elle est encore beaucoup utilisée ?
 
et n'existe-t-il pas une variante pour les processeurs 32 bits qui manipulent des nombres de 64 ou 128 bits ? (c'est à dire non plus inverser les bytes, mais des paquets de 4 bytes)


Lors d'une formation sur l'écriture de modules linux, le formateur nous a expliqué que le choix du processeur (i.e. son endianess) est déterminant pour les performances selon l'utilisation que l'on va en faire.  
Par exemple, une application qui va faire du traitement réseau (un routeur, un firewall etc ...) sera toujours moins performant (selon ses dires) sur un processeur intel que sur un processeur basé sur du big endian car la pile TCP/IP a été développée sur une base big endian, et donc sur un processeur intel, on passe son temps à convertir (le fameux htons ). Inversement, le bus PCI (et plus récemment USB) a été créé en collaboration avec intel et fonctionne donc en little endian.
Ce qui signifie que dans certains cas, selon le processeur utiliser, on va passer beaucoup de temps ou non à convertir les données.
 
(Je me suis peut etre trompé sur certains points, n'étant pas un expert, mais l'idée est là).

Reply

Marsh Posté le 01-08-2008 à 17:01:21    

Pour en revenir au sujet :

Joel F a écrit :

si tu utilise aussi le même attribut pour tes structures ca devrait passer. Ensuite à toi de remettre tes données dans une structure non-packed


Ok, on en revient alors au traitement au cas par cas que je devrais faire puisque ma structure varie grandement d'un cas à l'autre.

Reply

Marsh Posté le 01-08-2008 à 17:04:08    

je ne vois pas comment tu peut t'en sortir autrement.
Pourrais tu filer un exemple minimaliste de ce que tu as comme structure

Reply

Marsh Posté le 01-08-2008 à 17:08:17    

merci pour ces informations :jap:

Reply

Marsh Posté le 01-08-2008 à 17:08:36    

ouais
alors de tête(je l'ai pas sous les yeux)
struct __attribute__ ((__packed__)) {
int blabla;
int truc:6;
machinchose ma_struct;
}header 1 ;
 
struct __attribute__ ((__packed__)){
char monChar:1;
int monInt:7;
} machinchose;
 
avec bcp plus de variables, et bcp plus de structures imbriquées.
Et par exemple, si blabla=12, la structure imbriquée sera totalement différente que dans le cas blabla=13 ....


Message édité par Facewindu le 03-08-2008 à 18:47:23
Reply

Marsh Posté le 03-08-2008 à 12:32:55    

xilebo a écrit :


Lors d'une formation sur l'écriture de modules linux, le formateur nous a expliqué que le choix du processeur (i.e. son endianess) est déterminant pour les performances selon l'utilisation que l'on va en faire.
Par exemple, une application qui va faire du traitement réseau (un routeur, un firewall etc ...) sera toujours moins performant (selon ses dires) sur un processeur intel que sur un processeur basé sur du big endian car la pile TCP/IP a été développée sur une base big endian, et donc sur un processeur intel, on passe son temps à convertir (le fameux htons ).

 

Rien à voir avec l'archi initiale de dev de la pile DARPA. Cela vient du fait que le netwok byte order est BE alors que x86 est LE.

 

Maintenant, rien ne t'empeches de faire du code sale et de ne pas utiliser les htons et compagnie, du moment que les systèmes utiliseront la même convention aux deux bouts.

 

Il faut savoir que c'est une problèmatique qui ne s'applique qu'aux types binaires. Si la communication ne se fait qu'en chaine de caractères, on se fiche du BE/LE. D'ailleurs, les primitives htons/ntohs n'encapsulent pas toutes les conventions, si tu communiques des double, à toi de te faire ta moulinette, ou d'utiliser des usines à gaz comme XDR.

 

MagicBuzz> aujourd'hui, la mode n'est pas à l'économie de BP mais à la simplification du code, donc à s'astreint généralement la problèmatique BE/LE en évitant les types binaires, et en encapsulant les données sous forme de chaines de caractères (qui n'ont pas ce problème), quitte à utiliser des dialectes plus haut niveau comme XML, pour le typage.


Message édité par Gf4x3443 le 03-08-2008 à 12:33:49

---------------
Petit guide Kerberos pour l'administrateur pressé
Reply

Marsh Posté le 03-08-2008 à 21:14:12    

Rassure-moi, on ne fait pas du XML pour du bas niveau, tout de même ?


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 03-08-2008 à 21:23:11    

el muchacho a écrit :

Rassure-moi, on ne fait pas du XML pour du bas niveau, tout de même ?

 

Ca dépend, t'entends quoi par "bas niveau"?

 

Pour mon cas (netbsd), on s'en sert de plus en plus dans le noyau, avec un parser simplifié fait pour avoir le moins d'overhead possible (la proplib: http://www.daemon-systems.org/man/proplib.3.html ).

 

Apple fait la même chose, c'est plus clean pour passer des syscall/ioctl sans avoir à se préoccuper de types complexes ou abscons, ou faire des couches de compatibilités sans se péter les couilles (surtout que linux les fait à sa sauce, très particulière).

 

Niveau perf, aucune différence.

 

Sur réseau en revanche, j'ai jamais vu (à part pour les XML RPC, genre fermes de virtualisation - c'est à la mode, avec XMPP, ca permet de faire des trucs très sympa). XDR reste quand même la référence.


Message édité par Gf4x3443 le 03-08-2008 à 21:23:57

---------------
Petit guide Kerberos pour l'administrateur pressé
Reply

Marsh Posté le 03-08-2008 à 23:47:59    

xilebo a écrit :


Lors d'une formation sur l'écriture de modules linux, le formateur nous a expliqué que le choix du processeur (i.e. son endianess) est déterminant pour les performances selon l'utilisation que l'on va en faire.  
Par exemple, une application qui va faire du traitement réseau (un routeur, un firewall etc ...) sera toujours moins performant (selon ses dires) sur un processeur intel que sur un processeur basé sur du big endian car la pile TCP/IP a été développée sur une base big endian, et donc sur un processeur intel, on passe son temps à convertir (le fameux htons ). Inversement, le bus PCI (et plus récemment USB) a été créé en collaboration avec intel et fonctionne donc en little endian.
Ce qui signifie que dans certains cas, selon le processeur utiliser, on va passer beaucoup de temps ou non à convertir les données.
 
(Je me suis peut etre trompé sur certains points, n'étant pas un expert, mais l'idée est là).


 
bof.
le coût de transformation est plustôt ridicule devant le reste des traitements internes à la pile.

Reply

Marsh Posté le 06-08-2008 à 17:52:59    

Pour en revenir au sujet, je me fais des tableaux de char, contenant des 0 ou des 1. Ca me fait une sorte de tableau de bits, et après je me démerde avec au cas par cas.
donc y a plus de prob.
merci !

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed