¿Cómo convertir big endian a little endian en C sin utilizar funciones de biblioteca?
Necesito escribir una función para convertir un entero big endian en un entero little endian en C. No puedo usar ninguna función de biblioteca. ¿Cómo haría esto?
Suponiendo que lo que necesita es un simple intercambio de bytes, intente algo como
Conversión de 16 bits sin firmar:
swapped = (num>>8) | (num<<8);
Conversión de 32 bits sin firmar:
swapped = ((num>>24)&0xff) | // move byte 3 to byte 0
((num<<8)&0xff0000) | // move byte 1 to byte 2
((num>>8)&0xff00) | // move byte 2 to byte 1
((num<<24)&0xff000000); // byte 0 to byte 3
Esto intercambia los pedidos de bytes de las posiciones 1234 a 4321. Si su entrada fue 0xdeadbeef
, un intercambio endian de 32 bits podría tener una salida de 0xefbeadde
.
El código anterior debería limpiarse con macros o al menos constantes en lugar de números mágicos, pero espero que ayude tal como está.
EDITAR: como señaló otra respuesta, existen alternativas específicas de plataforma, sistema operativo y conjunto de instrucciones que pueden ser MUCHO más rápidas que las anteriores. En el kernel de Linux hay macros (cpu_to_be32 por ejemplo) que manejan bastante bien el endianismo. Pero estas alternativas son específicas de sus entornos. En la práctica, la mejor manera de abordar la endianidad es utilizando una combinación de enfoques disponibles.
Incluyendo:
#include <byteswap.h>
puede obtener una versión optimizada de las funciones de intercambio de bytes dependientes de la máquina. Luego, podrá utilizar fácilmente las siguientes funciones:
__bswap_32 (uint32_t input)
o
__bswap_16 (uint16_t input)
#include <stdint.h>
//! Byte swap unsigned short
uint16_t swap_uint16( uint16_t val )
{
return (val << 8) | (val >> 8 );
}
//! Byte swap short
int16_t swap_int16( int16_t val )
{
return (val << 8) | ((val >> 8) & 0xFF);
}
//! Byte swap unsigned int
uint32_t swap_uint32( uint32_t val )
{
val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF );
return (val << 16) | (val >> 16);
}
//! Byte swap int
int32_t swap_int32( int32_t val )
{
val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF );
return (val << 16) | ((val >> 16) & 0xFFFF);
}
Actualización : intercambio de bytes de 64 bits agregado
int64_t swap_int64( int64_t val )
{
val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
return (val << 32) | ((val >> 32) & 0xFFFFFFFFULL);
}
uint64_t swap_uint64( uint64_t val )
{
val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
return (val << 32) | (val >> 32);
}