Преобразование big endian в little endian при чтении из двоичного файла [дубликат]

этот вопрос уже есть ответ здесь:

Я искал, как преобразовать big-endian в little-endians. Но я не вижу ничего хорошего, что могло бы решить мою проблему. Кажется, есть много способов сделать это. преобразование. В любом случае этот следующий код работает нормально в системе big-endian. Но как написать функцию преобразования, чтобы она работала и в системе little-endian?

это домашнее задание, но это просто дополнительный, так как системы в школе работают с системой big-endian. Просто мне стало любопытно и захотелось, чтобы он работал и на моем домашнем компьютере!--3-->

#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;
}

решить

таким образом, Big-endian VS Little-endian - это просто обратный порядок байтов. Эта функция, которую я написал, кажется, служит моей цели в любом случае. Я добавил его сюда на случай, если в будущем он понадобится кому-то еще. Это только для double, хотя для integer либо используйте предложенную функцию torak, либо вы можете изменить этот код, сделав его только 4 байта.

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;
}

5 ответов


предполагая, что вы собираетесь продолжать, удобно хранить небольшой файл библиотеки вспомогательных функций. 2 из этих функций должны быть конечными свопами для 4 байтовых значений и 2 байтовых значений. Для некоторых твердых примеров (включая код) проверьте в этой статье.

Как только у вас есть функции swap, в любое время, когда вы читаете значение в неправильном endian, вызовите соответствующую функцию swap. Иногда камнем преткновения для людей здесь является то, что значения одного байта не должны если Вы читаете что-то вроде символьного потока, который представляет собой строку букв из файла, это должно быть хорошо. Только когда вы читаете в значении это несколько байтов (например, целое значение), вы должны поменять их местами.


вы можете использовать шаблон для вашего endian swap, который будет обобщен для типов данных:

#include <algorithm>

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

тогда ваш код будет выглядеть примерно так:

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;  

вас может заинтересовать ntohl семейство функций. Они предназначены для преобразования данных из сети в порядок байтов хоста. Порядок байтов сети является большим endian, поэтому в больших системах endian они ничего не делают, в то время как тот же код, скомпилированный на маленькой системе endian, будет выполнять соответствующие байтовые свопы.


Linux предоставляет endian.h, который имеет эффективные процедуры замены endian до 64-бит. Он также автоматически учитывает endianness вашей системы. 32-разрядные функции определяются следующим образом:

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

С аналогично названными функциями для 16 и 64-разрядных. Так что просто скажи

 x = le32toh(x);

преобразовать 32-разрядное целое число в прямой кодировки к узлу кодирования процессора. Это полезно для чтения данных little-endian.

 x = htole32(x);

преобразует из кодирование хоста до 32-битного little-endian. Это полезно для записи младший байт данных.

Примечание в системах BSD эквивалентный файл заголовка sys/endian.h


хорошо добавить, что MS поддерживает это на VS тоже проверьте эти встроенные функции:

  • htond
  • htonf
  • htonl
  • htonll
  • htons