J'ai besoin d'écrire une fonction pour convertir big endian en little endian en C. Je ne peux utiliser aucune fonction de bibliothèque.
c
swap
endianness
Alex Xander
la source
la source
Réponses:
En supposant que vous ayez besoin d'un simple échange d'octets, essayez quelque chose comme
Conversion 16 bits non signée:
Conversion 32 bits non signée:
Cela permute les ordres d'octets des positions 1234 à 4321. Si votre entrée l'était
0xdeadbeef
, un swap endian 32 bits pourrait avoir une sortie de0xefbeadde
.Le code ci-dessus devrait être nettoyé avec des macros ou au moins des constantes au lieu de nombres magiques, mais j'espère que cela aide tel quel
EDIT: comme une autre réponse l'a souligné, il existe des alternatives spécifiques à la plate-forme, au système d'exploitation et au jeu d'instructions qui peuvent être BEAUCOUP plus rapides que les précédentes. Dans le noyau Linux, il y a des macros (cpu_to_be32 par exemple) qui gèrent assez bien l'endianness. Mais ces alternatives sont spécifiques à leurs environnements. Dans la pratique, l'endianité est mieux traitée en utilisant un mélange d'approches disponibles
la source
((num & 0xff) >> 8) | (num << 8)
, gcc 4.8.3 génère une seulerol
instruction. Et si la conversion 32 bits est écrite comme((num & 0xff000000) >> 24) | ((num & 0x00ff0000) >> 8) | ((num & 0x0000ff00) << 8) | (num << 24)
, le même compilateur génère une seulebswap
instruction.struct byte_t reverse(struct byte_t b) { struct byte_t rev; rev.ba = b.bh; rev.bb = b.bg; rev.bc = b.bf; rev.bd = b.be; rev.be = b.bd; rev.bf = b.bc; rev.bg = b.bb; rev.bh = b.ba; return rev;}
où c'est un champ de bits avec 8 champs de 1 bit chacun. Mais je ne sais pas si c'est aussi rapide que les autres suggestions. Pour les entiers, utilisezunion { int i; byte_t[sizeof(int)]; }
pour inverser octet par octet dans l'entier.En incluant:
vous pouvez obtenir une version optimisée des fonctions de permutation d'octets dépendant de la machine. Ensuite, vous pouvez facilement utiliser les fonctions suivantes:
ou
la source
#include <byteswap.h>
, voir le commentaire dans le fichier .h lui-même. Ce message contient des informations utiles, j'ai donc voté à la hausse malgré que l'auteur ignore l'exigence de l'OP de ne pas utiliser une fonction lib.Mise à jour : Ajout de l'échange d'octets 64 bits
la source
int32_t
etint64_t
, quel est le raisonnement derrière le masquage de... & 0xFFFF
et... & 0xFFFFFFFFULL
? Y a-t-il quelque chose qui se passe avec l'extension de signe ici que je ne vois pas? Aussi, pourquoiswap_int64
revient-iluint64_t
? Cela ne devrait-il pas être le casint64_t
?swap_int64
dans votre réponse. +1 pour la réponse utile, BTW!LL
sont inutiles dans un(u)swap_uint64()
peu comme unL
n'est pas nécessaire dans(u)swap_uint32()
. LeU
n'est pas nécessaire dans unuswap_uint64()
peu comme leU
n'est pas nécessaire dansuswap_uint32()
Voici une version assez générique; Je ne l'ai pas compilé, donc il y a probablement des fautes de frappe, mais vous devriez avoir l'idée,
NB: Ceci n'est pas optimisé pour la vitesse ou l'espace. Il se veut clair (facile à déboguer) et portable.
Mise à jour 04/04/2018 Ajout de assert () pour piéger le cas invalide de n == 0, comme repéré par le commentateur @chux.
la source
bswap
instruction par un compilateur X86 décent avec l'optimisation activée. Cette version avec un paramètre pour la taille ne pouvait pas faire cela.Si vous avez besoin de macros (par exemple, système embarqué):
la source
UINT
dans leur nom.Edit: ce sont des fonctions de bibliothèque. Les suivre est la manière manuelle de le faire.
Je suis absolument abasourdi par le nombre de personnes qui ne connaissent pas __byteswap_ushort, __byteswap_ulong et __byteswap_uint64 . Bien sûr, ils sont spécifiques à Visual C ++, mais ils se compilent en un code délicieux sur les architectures x86 / IA-64. :)
Voici une utilisation explicite de l'
bswap
instruction, tirée de cette page . Notez que la forme intrinsèque ci-dessus sera toujours plus rapide que cela , je l'ai seulement ajoutée pour donner une réponse sans routine de bibliothèque.la source
Comme une blague:
la source
int i, size_t sizeofInt
et pas du même type pour les deux.voici un moyen d'utiliser l'instruction SSSE3 pshufb en utilisant son Intel intrinsèque, en supposant que vous ayez un multiple de 4
int
s:la source
Est-ce que cela fonctionnera / sera plus rapide?
la source
char
, nonbyte
.Voici une fonction que j'ai utilisée - testée et fonctionne sur n'importe quel type de données de base:
la source
source
est aligné selon les besoins - mais si cette hypothèse ne tient pas, le code est UB.EDIT: Cette fonction n'échange que l'endianité des mots alignés de 16 bits. Une fonction souvent nécessaire pour les encodages UTF-16 / UCS-2. MODIFIER FIN.
Si vous souhaitez modifier la finalité d'un bloc de mémoire, vous pouvez utiliser mon approche extrêmement rapide. Votre matrice de mémoire doit avoir une taille multiple de 8.
Ce type de fonction est utile pour modifier l'extrémité des fichiers Unicode UCS-2 / UTF-16.
la source
t know if it
aussi rapide que les suggestions mais ça marche: github.com/heatblazer/helpers/blob/master/utils.hCHAR_BIT
au lieu de8
est curieux comme0xFF00FF00FF00FF00ULL
dépend deCHAR_BIT == 8
. Notez que ceLL
n'est pas nécessaire dans la constante.CHAR_BIT
pour augmenter l'exposition de cette macro. Quant au LL, c'est plus une annotation qu'autre chose. C'est aussi une habitude que j'ai prise il y a longtemps avec des compilateurs buggy (pré-standard) qui ne feraient pas la bonne chose.Cet extrait de code peut convertir un petit nombre Endian 32 bits en un nombre Big Endian.
la source
((i>>24)&0xff) | ((i>>8)&0xff00) | ((i&0xff00)<<8) | (i<<24);
peut être plus rapide sur certaines plates-formes (par exemple, le recyclage des constantes de masque AND). La plupart des compilateurs le feraient, cependant, mais certains compilateurs simples ne sont pas en mesure de l'optimiser pour vous.Si vous utilisez un processeur x86 ou x86_64, le big endian est natif. alors
pour les valeurs 16 bits
pour les valeurs 32 bits
Ce n'est pas la solution la plus efficace, sauf si le compilateur reconnaît qu'il s'agit d'une manipulation au niveau des octets et génère du code de permutation d'octets. Mais cela ne dépend d'aucune astuce de disposition de la mémoire et peut être transformé en macro assez facilement.
la source