conversion fichier binaire Big-Little Endian [RESOLU] [C] - C - Programmation
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.
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 ?
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
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 ?
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.
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.
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
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.
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 ?
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
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)
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 ?
Marsh Posté le 01-08-2008 à 16:15:02
nan mais je ne parle pas d'arrêter le support sur les processeurs (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é
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 :
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.
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 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
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 ? |
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à).
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.
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
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 ....
Marsh Posté le 03-08-2008 à 12:32:55
xilebo a écrit :
|
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.
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 ?
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.
Marsh Posté le 03-08-2008 à 23:47:59
xilebo a écrit : |
bof.
le coût de transformation est plustôt ridicule devant le reste des traitements internes à la pile.
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 !
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