Convertir Little Endian à Big Endian
Je veux juste vous demander si ma méthode est correcte pour convertir de en little endian à big endian, juste pour s'assurer que, si je comprends la différence.
J'ai un certain nombre qui est stocké dans little-endian, voici le binaire et hexadécimal représentations du numéro:
0001 0010 0011 0100 0101 0110 0111 1000
12345678
En format big-endian je crois que les octets doivent être échangés, comme ceci:
1000 0111 0110 0101 0100 0011 0010 0001
87654321
Est-ce correct?
Aussi, le code ci-dessous tente de le faire, mais échoue. Est-il rien de manifestement erronée ou puis-je optimiser quelque chose? Si le code est mauvais pour cette conversion pouvez-vous expliquer pourquoi et montrent une meilleure méthode est de faire la même conversion?
uint32_t num = 0x12345678;
uint32_t b0,b1,b2,b3,b4,b5,b6,b7;
uint32_t res = 0;
b0 = (num & 0xf) << 28;
b1 = (num & 0xf0) << 24;
b2 = (num & 0xf00) << 20;
b3 = (num & 0xf000) << 16;
b4 = (num & 0xf0000) << 12;
b5 = (num & 0xf00000) << 8;
b6 = (num & 0xf000000) << 4;
b7 = (num & 0xf0000000) << 4;
res = b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7;
printf("%d\n", res);
- Vous pouvez utiliser un meilleur exemple de séquence de bits comme "0001 0010 0011 0100 0101 0110 0111 1000"
- Votre code est-à grignoter à base de (4 bits) au lieu de l'octet de base (8 bits). C'est en prenant une valeur de 32 bits et l'inversion de l'ordre des amuse-gueules. Je pense que vous avez voulu 64 bits des valeurs des octets en fonction. Aussi, les changements ne fonctionne pas depuis ce passage, ne tourne pas. Donc vous perdrez bits "à la fin". Et de la ranger un peu, pensez à utiliser un tableau plutôt discret
b1
,b2
, etc. - Je suis en train de faire cette opération en fonction de la tâche suivante: "Un 32 bits valeur numérique représentée par la représentation hexadécimale (st uv wx yz) doit être enregistré dans les quatre octets de terrain (st uv wx yz)." Donc, Si je voudrais faire la même chose mais au lieu de prendre 8 bits (1 octet), cela fonctionnera ?
- Vos exemples sont 64 bits. Si vous voulait vraiment dire 32 bits?
- Oui c'est un 32 bits exemple. Il pourrait être mon erreur que j'ai pris 64 bits au lieu de 32 bits. Mais il faut vraiment être de 32 bits.
- Ne pas faire la conversion vous-même, la plupart des plates-formes offrent des fonctions permettant de faire ceci:
htobe32
,htonl
, etc. si vous voulez la portabilité, l'utilisation d'un en-tête comme ceci. - Double Possible de convertir big endian à little endian dans C [sans l'aide fournie func]
Vous devez vous connecter pour publier un commentaire.
OP un exemple de code est incorrect.
Endian la conversion fonctionne à l'bits et 8 bits de l'octet. La plupart des endian questions face à niveau de l'octet. OP code est en train de faire un endian changement lors de la 4-bits grignoter niveau de. Conseille plutôt:
Si la performance est vraiment important, le processeur particulier aurait besoin d'être connu. Sinon, laisser le compilateur.
[Modifier] OP ajouté un commentaire qui change les choses.
"32 bits valeur numérique représentée par la représentation hexadécimale (st uv wx yz) doit être enregistré dans les quatre octets de terrain (st uv wx yz)."
Il apparaît dans ce cas, le endian du nombre de 32 bits est inconnu et le résultat doit être stocker dans la mémoire de peu endian commande.
[2016 Modifier] La Simplification
À l'aide d'un
u
après la maj constantes (à droite opérandes) résultats dans la même sans elle.union JPEndian { uint32_t u32; uint8_t u8[4]; };
JPEndian.u8[0] = (uint8_t) (num >> 0u); ... printf("%" PRIX32 "\n", JPEndian.u32);
Je pense que vous pouvez utiliser la fonction
htonl()
. Ordre des octets de réseau est en big endian.htonl()
n'est pas dans la bibliothèque standard C malheureusement, nécessitant une re-mise en œuvre. Certains les implémentations de retouruint32_t
, d'autresunsigned long
. hton32() fixe la taille.Désolé, ma réponse est un peu trop tard, mais il semble que personne n'a mentionné les fonctions intégrées d'inverser l'ordre des octets, ce qui en très important en termes de performances.
La plupart des processeurs modernes sont little-endian, alors que tous les protocoles réseau sont big-endian. C'est l'histoire et plus que vous pouvez trouver sur Wikipédia. Mais cela signifie que nos processeurs convertir entre little et big-endian des millions de fois alors que nous naviguer sur Internet.
C'est pourquoi la plupart des architectures ont un processeur dédié instructions pour faciliter cette tâche. Pour les architectures x86, il est
BSWAP
instruction, et pour les Armes il y aREV
. C'est le moyen le plus efficace pour inverser l'ordre des octets de.Pour éviter d'assemblage dans notre code en C, on peut utiliser les haut-ins à la place. Pour GCC, il est
__builtin_bswap32()
fonction et pour Visual C++, il est_byteswap_ulong()
. Ces fonctions vont générer juste une instruction du processeur sur la plupart des architectures.Voici un exemple:
Voici le rapport généré:
Et voici le démontage (sans optimisation, c'est à dire
-O0
):Il y a juste un
BSWAP
instruction en effet.Donc, si nous nous soucions de la performance, nous devrions utiliser ces fonctions intégrées à la place de toute autre méthode d'octets de l'inversion. Juste mes 2 cents.
"Je swap de chacun des octets de droite?" -> oui, pour convertir entre little et big endian, à vous de donner les octets de l'ordre opposé.
Mais dans un premier temps de réaliser quelques petites choses:
uint32_t
est 32bits, qui est de 4 octets, qui est de 8 chiffres hexadécimaux0xf
récupère les 4 bits de poids faible, pour récupérer les 8 bits, vous devez0xff
donc, dans le cas où vous souhaitez changer l'ordre de 4 octets avec ce genre de masques, vous pouvez:
Vous pourriez faire ceci:
Je suis en supposant que vous êtes sur linux
Inclure
"byteswap.h"
& Utiliserint32_t bswap_32(int32_t argument);
Il est logique vue En voir,
/usr/include/byteswap.h
Une manière légèrement différente de s'attaquer à ce qui peut parfois être utile, c'est d'avoir une union de seize ou trente-deux bits de valeur et un tableau de caractères. J'ai juste fait cela lors de l'obtention de série de messages qui entrent dans la big endian ordre, mais travaille sur un little endian micro.
union MessageLengthUnion
{
};
Alors quand je reçois les messages j'ai mis le premier reçu uint8 dans .asChars[1], la deuxième en .asChars[0] puis-je y accéder dans le .asInt partie de l'union dans le reste de mon programme. Si vous disposez d'un délai de trente-deux bits de la valeur à stocker, vous pouvez avoir la matrice de quatre de long.
une suggestion :
OP code est incorrect pour les raisons suivantes:
<<
opérations de la finale à quatre swaps sont incorrects, ils devraient être shift-droit>>
des opérations et de leur quart de valeurs doivent également être corrigées.Considérons le code suivant, qui convertit de manière efficace une valeur non signée:
Le résultat est représenté ici à la fois binaire et hexadécimal, remarquez comment les octets ont été inversées:
Optimisation
En termes de performance, de laisser le compilateur d'optimiser votre code lorsque cela est possible. Vous devriez éviter les structures de données comme des tableaux pour des algorithmes simples comme ça, donc va généralement la cause de l'autre mode de comportement, tels que l'accès à la RAM au lieu d'utiliser des registres du CPU.
Un Simple programme en C pour convertir à partir de petits à gros
Vous pouvez utiliser la lib fonctions. Ils se résument à l'assemblée, mais si vous êtes ouverts à de nouvelles implémentations en C, ils sont ici (en supposant que l'int est de 32 bits) :
Et l'utilisation est effectuée comme suit: