web-dev-qa-db-fra.com

Convertir un gros endian en petit endian lors de la lecture à partir d'un fichier binaire

J'ai cherché comment convertir le big-endian en little-endians. Mais je n'ai trouvé aucun bien qui pourrait résoudre mon problème. Il semble qu'il y ait plusieurs façons de faire cette conversion. Quoi qu'il en soit, ce code suivant fonctionne correctement dans un système big-endian. Mais comment dois-je écrire une fonction de conversion pour qu'elle fonctionne également sur le système little-endian?

C'est un devoir, mais c'est juste un extra puisque les systèmes à l'école fonctionnent avec un système big-endian. C'est juste que je suis devenu curieux et que je voulais que ça marche aussi sur mon ordinateur personnel

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
   ifstream file;

   file.open("file.bin", ios::in | ios::binary);

   if(!file)
      cerr << "Not able to read" << endl;
   else
   {
      cout << "Opened" << endl;

      int i_var;
      double d_var;

      while(!file.eof())
      {
         file.read( reinterpret_cast<char*>(&i_var) , sizeof(int) );
         file.read( reinterpret_cast<char*>(&d_var) , sizeof(double) );
         cout << i_var << " " << d_var << endl;
      }
   }
   return 0;
}

Résol

Donc Big-endian VS Little-endian n'est qu'un ordre inverse des octets. Cette fonction que j'ai écrite semble de toute façon servir mon objectif. Je l'ai ajouté ici au cas où quelqu'un d'autre en aurait besoin à l'avenir. Ceci n'est valable que pour le double, pour l'entier, utilisez la fonction suggérée par torak ou vous pouvez modifier ce code en le faisant échanger uniquement sur 4 octets.

double swap(double d)
{
   double a;
   unsigned char *dst = (unsigned char *)&a;
   unsigned char *src = (unsigned char *)&d;

   dst[0] = src[7];
   dst[1] = src[6];
   dst[2] = src[5];
   dst[3] = src[4];
   dst[4] = src[3];
   dst[5] = src[2];
   dst[6] = src[1];
   dst[7] = src[0];

   return a;
}
18
starcorn

En supposant que vous allez continuer, il est pratique de conserver un petit fichier de bibliothèque de fonctions d'assistance. 2 de ces fonctions doivent être des échanges endiens pour des valeurs de 4 octets et des valeurs de 2 octets. Pour quelques exemples solides (y compris le code), consultez cet article .

Une fois que vous avez vos fonctions de swap, chaque fois que vous lisez une valeur dans le mauvais endian, appelez la fonction de swap appropriée. Parfois, un point d'achoppement pour les gens ici est que les valeurs d'un seul octet n'ont pas besoin d'être échangées en endian, donc si vous lisez quelque chose comme un flux de caractères qui représente une chaîne de lettres d'un fichier, cela devrait être bon. Ce n'est que lorsque vous lisez une valeur qu'il s'agit de plusieurs octets (comme une valeur entière) que vous devez les échanger.

2
Bryan

Vous pouvez utiliser un modèle pour votre échange endian qui sera généralisé pour les types de données:

#include <algorithm>

template <class T>
void endswap(T *objp)
{
  unsigned char *memp = reinterpret_cast<unsigned char*>(objp);
  std::reverse(memp, memp + sizeof(T));
}

Ensuite, votre code finirait par ressembler à quelque chose comme:

file.read( reinterpret_cast<char*>(&i_var) , sizeof(int) );
endswap( &i_var );
file.read( reinterpret_cast<char*>(&d_var) , sizeof(double) );  
endswap( &d_var );
cout << i_var << " " << d_var << endl;  
21
Dingo

Linux fournit endian.h, qui a des routines de permutation endiennes efficaces jusqu'à 64 bits. Il prend également en compte automatiquement l'endianité de votre système. Les fonctions 32 bits sont définies comme suit:

uint32_t htobe32(uint32_t Host_32bits);           // Host to big-endian encoding
uint32_t htole32(uint32_t Host_32bits);           // Host to lil-endian encoding
uint32_t be32toh(uint32_t big_endian_32bits);     // big-endian to Host encoding
uint32_t le32toh(uint32_t little_endian_32bits);  // lil-endian to Host encoding

avec des fonctions portant le même nom pour 16 et 64 bits. Alors tu dis juste

 x = le32toh(x);

pour convertir un entier 32 bits dans le codage little-endian en codage CPU hôte. Ceci est utile pour lire des données peu endiennes.

 x = htole32(x);

convertira de l'encodage Host en petit-boutien 32 bits. Ceci est utile pour écrire des données peu endiennes.

Remarque sur les systèmes BSD, le fichier d'en-tête équivalent est sys/endian.h

4
QuasarDonkey

Vous pourriez être intéressé par la famille de fonctions ntohl . Ceux-ci sont conçus pour transformer les données du réseau en ordre d'octets de l'hôte. L'ordre des octets réseau est big endian, donc sur les systèmes big endian ils ne font rien, tandis que le même code compilé sur un petit système endian effectuera les échanges d'octets appropriés.

4
torak

Il est bon d'ajouter que MS a ceci pris en charge sur VS aussi vérifiez ces fonctions en ligne:

  • htond
  • htonf
  • htonl
  • htonll
  • htons
2
Mahmoud Fayez