9
votes

Comment convertir une valeur de l'ordre d'octet hôte à Little Endian?

J'ai besoin de convertir une courte valeur de l'ordre d'octet de l'hôte à peu d'Endian. Si la cible était grande Endian, je pourrais utiliser la fonction HTS (), mais hélas - ce n'est pas.

Je suppose que je pouvais faire: xxx

mais cela pourrait potentiellement Parce que les octets doivent être échangés deux fois, rendant le résultat correct mais me donnant une pénalité de performance qui n'est pas correcte dans mon cas.


4 commentaires

Ne vous inquiétez pas de la pénalité de performance. Si vous faites des choses redondantes (échangeez un INT deux fois), le compilateur détectera cela et supprimera le code pendant sa phase d'optimisation.


Ce que NILS a dit, mais une approche plus prudente consiste à vérifier le code généré au premier plan au niveau d'optimisation que vous pouvez vous permettre (si vous êtes coincé avec débogage, alors uh-oh). Si le double échange est optimisé, votre problème de performance est résolu instantanément.


Le compilateur réussira-t-il vraiment à optimiser cela? Je suppose que si Swap () et les jonces () sont des macros ou des fonctions en ligne, mais sinon?


Ça dépend. Parfois, les compilateurs peuvent s'intéresser automatiquement (ou par la génération de code temporel de liaison), parfois il faut indiquer l'utilisation de la compilation (forcée) en ligne ou à utiliser la compilation de module transversale ... Les conseils exacts sont difficiles sans essayer d'abord.


7 Réponses :


6
votes

Ensuite, vous devez connaître votre endianness et appeler des jonces () conditionnellement. En réalité, même pas les jos, mais simplement échanger des octets conditionnellement. Compiler le temps, bien sûr.


1 commentaires

+1. Si vous transpirez sur la performance, #Ifdef est votre ami ici.



0
votes

Cet astuce devrait: Au démarrage, utilisez NTOHS avec une valeur nominale, puis comparez la valeur résultante à la valeur d'origine. Si les deux valeurs sont identiques, la machine utilise Big Endian, sinon il est petit Endian.

Ensuite, utilisez une méthode Tolittletletletendian qui ne fait rien ou invoque NTOHS , en fonction du résultat du test initial.

(édité avec les informations fournies dans Commentaires)


3 commentaires

Avez-vous remarqué que l'OP est préoccupé par la pénalité de la performance? ;-)


L'OP n'a besoin que de faire cette vérification une fois, au démarrage.


FlyfishR64 et vérifiez les résultats à chaque fois. Ne redragez jamais jusqu'à l'exécution de ce que vous pouvez faire au moment de la compilation.



8
votes

Voici un article sur l'endanse et comment le déterminer à partir d'IBM:

Ecrire un code indépendant de Endian en C: Ne laissez pas l'endansement" octet "vous

Il comprend un exemple de la procédure d'endentialité au moment de l'exécution (que vous auriez besoin de faire une seule fois) xxx

La page dispose également d'une section sur les méthodes d'inversion de l'ordre d'octet: xxx

; xxx


5 commentaires

Vérifie-t-elle une condition mieux que de faire un échange supplémentaire?


Le point de ceci est pour 1. Faire le code portable et 2. Ne faites que l'échange sur les plates-formes qui ne sont déjà pas peu d'Endian. Dans le cas où le système est déjà petit Endian, vous vous retrouvez avec un test et un saut contre 4 swaps d'octets.


Une autre chose, puisque le conditionnel ne change jamais #define is_bigendien () ((* (char *) & i) == 0) , je suppose que le prédicteur de la branche sur la CPU l'éliminera probablement sur cela devenant efficacement un noop lorsque le système est déjà petit Endian.


La bonne idée de cette technique est que cela fonctionnera sur des systèmes qui ne disposent pas des fonctions NTOHS (). En outre, Swap ne fonctionne généralement que avec deux paramètres. Cette méthode permet une expansion en largeurs entières comportant plus de 2 octets.


Dans la première mise en œuvre de la réversibilité (), C1 doit être réalisée à court terme dans la deuxième déclaration de retour avant de transférer les bits. Sinon, ils vont juste finir par aller au grand seau dans le ciel.



0
votes

ma règle de performance de la règle est que cela dépend si vous êtes petit-Endian-ising un gros bloc de données en une seule fois, ou une seule valeur:

Si une seule valeur, la fonction d'appel est une seule valeur. Allumer probablement la surcharge des swaps inutiles d'octets, et c'est même si le compilateur n'offre pas les swaps d'octets inutiles. Ensuite, vous allez peut-être écrire la valeur comme numéro de port d'une connexion à socket et essayer d'ouvrir ou de lier une prise, qui prend un âge comparé à tout type de manipulation bit. Alors, ne vous inquiétez pas à ce sujet.

Si un grand bloc, vous pourriez vous inquiéter, le compilateur ne le gérera pas. Alors, faites quelque chose comme ceci: xxx

ou examinez les instructions de SIMD sur votre architecture qui peut le faire considérablement plus rapidement.

écrire is_little_endian () en utilisant n'importe quelle chose que vous aimez. Je pense que le seul Robert S. Barnes fournit est un son, mais comme vous le savez habituellement pour une cible donnée, que ce soit à grande ou petite-Endian, vous devriez peut-être avoir un fichier d'en-tête spécifique à la plate-forme, qui le définit comme une Macro évaluant soit à 1 ou 0.

Comme toujours, si vous vous souciez vraiment de la performance, regardez l'ensemble généré pour voir si le code non inutile a été supprimé ou non, et le temps des différentes alternatives les unes voir ce qui va réellement le plus rapide.


0 commentaires

4
votes

quelque chose comme ce qui suit: xxx

Si vous avez un système correctement configuré (tel que le préprocesseur sait si l'ID cible Little ou Big Endian) Vous obtenez une version "optimisée" de HTHOLES () . Sinon, vous obtenez la version potentiellement non optimisée qui dépend de htons () . En tout cas, vous obtenez quelque chose qui fonctionne.

rien de trop délicat et plus ou moins portable.

Bien sûr, vous pouvez améliorer encore les possibilités d'optimisation en la mettant en œuvre avec Inline ou sous forme de macros comme vous le voyez.

Vous voudrez peut-être regarder quelque chose comme le "Harnais portable Open Source (Posh)" pour une implémentation réelle qui définit l'endansion pour divers compilateurs. Remarque, l'accession à la bibliothèque nécessite une page de pseudo-authentification (bien que vous n'ayez pas besoin de vous inscrire pour donner des informations personnelles): http://hookatooka.com/poshlib/


1 commentaires

Exactement ce que je cherchais. Je suis dans un environnement Linux / GCC, donc en incluant , __byte_order est défini comme __Little_endian ou __big_endian (ou __pdp_endian)



0
votes

Malheureusement, il n'y a pas vraiment de manière croisée à la plate-forme de déterminer l'ordre d'octet d'un système au moment de la compilation avec Standard C. Je suggère d'ajouter un #define à votre config.h (ou quoi que ce soit d'autre que vous ou votre système de construction utilise pour la configuration de construction).

Un test d'unité Pour vérifier la définition correcte de Little_endian ou Big_endian pourrait ressembler Ceci: xxx


0 commentaires

0
votes

sur de nombreux systèmes Linux, il existe un ou avec des fonctions de conversion. Page d'homme pour Endian (3)


0 commentaires