2010-09-29 24 views
15

He estado buscando cómo convertir big-endian a little-endians. Pero no encontré ningún bien que pudiera resolver mi problema. Parece que hay muchas formas en que puedes hacer esta conversión. De todos modos, este código siguiente funciona bien en un sistema big-endian. Pero, ¿cómo debería escribir una función de conversión para que también funcione en el sistema little-endian?Convertir big endian a little endian al leer de un archivo binario

Esta es una tarea, pero es solo un extra ya que los sistemas en la escuela ejecutan el sistema big-endian. Es sólo que me picó la curiosidad y quería hacer que funcione en mi ordenador personal también

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

Resuelto

Así Big-endian VS ascendente hacia la izquierda es sólo un orden inverso de los bytes. Esta función que escribí parece servir a mi propósito de todos modos. Lo agregué aquí en caso de que alguien más lo necesite en el futuro. Sin embargo, esto solo es para el doble, para enteros use la función recomendada por torak o puede modificar este código haciendo que intercambie solo 4 bytes.

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

Incluso si resolvió su problema de endianess, los formatos de coma flotante pueden variar entre las plataformas. No puede guardar valores de coma flotante binarios en una plataforma y esperar cargarlos en otra. ¿Es un requisito que hagas este binario? – sbi

+0

bien, no es un requisito ya que la tarea debe ser hecha y mostrada en las computadoras de la escuela. Es solo mi curiosidad que quiero saber cómo leer este archivo binario en una computadora con Windows. – starcorn

+1

@sbi: ¿qué plataformas tienen implementado en la actualidad punto flotante en dispositivos que no sean IEE-754? – Kos

Respuesta

2

Suponiendo que va a continuar, es útil mantener un pequeño archivo de biblioteca de funciones de ayuda. 2 de esas funciones deberían ser intercambios endian para valores de 4 bytes y valores de 2 bytes. Para algunos ejemplos sólidos (incluido el código) echa un vistazo a this article.

Una vez que tenga sus funciones de intercambio, cada vez que lea un valor en el endian equivocado, llame a la función de intercambio adecuada. A veces, un punto de tropiezo para las personas aquí es que los valores de un solo byte no necesitan ser intercambiados por endian, por lo que si estás leyendo algo así como un flujo de caracteres que representa una cadena de letras de un archivo, eso debería ser bueno. Solo cuando está leyendo en un valor esto es múltiples bytes (como un valor entero) que tiene que intercambiarlos.

+0

en realidad me confundo ya que hay muchos cambios diferentes. En ese artículo, se trataba de swaps de corto, largo y flotante. ¿Funcionará alguno de esos intercambios para los tipos de datos con los que estoy trabajando? – starcorn

+0

Las soluciones dependen del tamaño de su valor de datos. Si tiene un valor de 2 bytes, use 'ShortSwap()', si tiene un valor de 4 bytes 'LongSwap().' El 'FloatSwap()' en el ejemplo no tiene ningún sentido, excepto que hay una lógica diferencia entre almacenamiento flotante y almacenamiento prolongado ... Sin embargo, LongSwap aún funcionará correctamente en un flotador de 4 bytes. Lo que hizo en su solución publicada arriba es efectivamente lo mismo para un valor de 8 bytes. – Bryan

+0

¡El enlace es 404 ahora! –

4

Puede que le interese la familia de funciones ntohl. Están diseñados para transformar datos de una red a una orden de bytes de host. El orden de bytes de red es big endian, por lo tanto, en los sistemas de big endian no hacen nada, mientras que el mismo código compilado en un sistema little endian realizará los swaps de bytes apropiados.

+0

¿hay algo similar para el doble? – starcorn

+1

La forma en que se representan los números de coma flotante es más complicada (y variada) que para los itegers, y nunca lo he intentado, así que no estoy 100% seguro. Sin embargo, suponiendo que las representaciones de coma flotante en las dos máquinas coincidan (excepto en endianness), el artículo con el que Bryan se vincula sugiere que debería ser posible. – torak

19

Se podría utilizar una plantilla para su canje endian que será generalizada para los tipos de datos:

#include <algorithm> 

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

A continuación, el código podría terminar buscando algo como:

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; 
+0

Tengo algo similar, pero tomando el objeto por referencia, en lugar de puntero. – sbi

4

Linux proporciona endian.h, que tiene rutinas de intercambio endian eficientes de hasta 64 bits. También cuenta automágicamente para el endianness de su sistema. Las funciones de 32 bits se definen así:

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 

con funciones de nombre similar para 16 y 64 bits. Por lo que acaba de decir

x = le32toh(x); 

para convertir un entero de 32 bits en la codificación ascendente hacia la izquierda a la codificación de la CPU host. Esto es útil para leer datos little-endian.

x = htole32(x); 

convertirá de la codificación del host a 32-bit little-endian. Esto es útil para escribir datos little-endian.

Nota sobre los sistemas BSD, el archivo de cabecera equivalente es sys/endian.h

+1

También tenga cuidado porque el encabezado BSD * * no es seguro para el ensamblado, lo que significa que no puede incluirlo en ningún archivo de ensamblaje que sea parte de su programa C/C++. Esto me atrapó porque después de leer el encabezado 'endian.h' de Linux, asumí implícitamente que todos los encabezados' endian.h' eran solo de preprocesador, lo cual es incorrecto. Solo poner esto aquí para evitar que alguien más caiga en la misma trampa. – Thomas

2

Es bueno agregar que la EM tiene que ver esto con el apoyo de VS también comprobar esto funciones en línea:

  • htond
  • htonf
  • htonl
  • htonll
  • htons
Cuestiones relacionadas