Necesito escribir una función para convertir big endian a little endian en C. No puedo usar ninguna función de biblioteca.
c
swap
endianness
Alex Xander
fuente
fuente
Respuestas:
Suponiendo que lo que necesita es un simple intercambio de bytes, intente algo como
Conversión de 16 bits sin signo:
Conversión de 32 bits sin signo:
Esto intercambia las órdenes de bytes de las posiciones 1234 a 4321. Si su entrada fue
0xdeadbeef
, un intercambio endian de 32 bits podría tener una salida de0xefbeadde
.El código anterior debe limpiarse con macros o al menos constantes en lugar de números mágicos, pero es de esperar que ayude 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 el endianness bastante bien. Pero estas alternativas son específicas de sus entornos. En la práctica, la endianidad se aborda mejor utilizando una combinación de enfoques disponibles.
fuente
((num & 0xff) >> 8) | (num << 8)
, gcc 4.8.3 genera una únicarol
instrucción. Y si la conversión de 32 bits se escribe como((num & 0xff000000) >> 24) | ((num & 0x00ff0000) >> 8) | ((num & 0x0000ff00) << 8) | (num << 24)
, el mismo compilador genera una solabswap
instrucción.struct byte_t reverse(struct byte_t b) { struct byte_t rev; rev.ba = b.bh; rev.bb = b.bg; rev.bc = b.bf; rev.bd = b.be; rev.be = b.bd; rev.bf = b.bc; rev.bg = b.bb; rev.bh = b.ba; return rev;}
con campos de bits como este: donde este es un campo de bits con 8 campos de 1 bit cada uno. Pero no estoy seguro de si eso es tan rápido como las otras sugerencias. Para enteros, utiliceunion { int i; byte_t[sizeof(int)]; }
para invertir byte por byte en el entero.Incluyendo:
puede obtener una versión optimizada de las funciones de intercambio de bytes dependientes de la máquina. Entonces, puede usar fácilmente las siguientes funciones:
o
fuente
#include <byteswap.h>
, consulte el comentario en el archivo .h. Esta publicación contiene información útil, así que voté a pesar de que el autor ignoró el requisito de OP de no usar una función lib.Actualización : intercambio de bytes de 64 bits agregado
fuente
int32_t
yint64_t
, ¿cuál es el razonamiento detrás del enmascaramiento de... & 0xFFFF
y... & 0xFFFFFFFFULL
? ¿Está sucediendo algo con la extensión de señal aquí que no veo? Además, ¿por quéswap_int64
regresauint64_t
? ¿No debería ser asíint64_t
?swap_int64
en su respuesta. +1 para la respuesta útil, ¡por cierto!LL
son innecesarias en(u)swap_uint64()
gran parte como unL
no es necesario en(u)swap_uint32()
. ElU
no es necesario enuswap_uint64()
mucho como elU
no es necesario enuswap_uint32()
Aquí hay una versión bastante genérica; No lo he compilado, por lo que probablemente haya errores tipográficos, pero debería hacerse una idea,
NB: Esto no estáoptimizado para velocidad o espacio. Está destinado a ser claro (fácil de depurar) y portátil.
Actualización 2018-04-04 Se agregó el assert () para atrapar el caso no válido de n == 0, como lo detectó el comentarista @chux.
fuente
bswap
instrucción por un compilador X86 decente con optimización habilitada. Esta versión con un parámetro para el tamaño no pudo hacer eso.Si necesita macros (por ejemplo, sistema integrado):
fuente
UINT
en su nombre.Editar: estas son funciones de biblioteca. Seguirlos es la forma manual de hacerlo.
Estoy absolutamente sorprendido por la cantidad de personas que desconocen __byteswap_ushort, __byteswap_ulong y __byteswap_uint64 . Seguro que son específicos de Visual C ++, pero se compilan en un código delicioso en arquitecturas x86 / IA-64. :)
Aquí hay un uso explícito de la
bswap
instrucción, extraído de esta página . Tenga en cuenta que la forma intrínseca anterior siempre será más rápida que esta , solo la agregué para dar una respuesta sin una rutina de biblioteca.fuente
Como una broma:
fuente
int i, size_t sizeofInt
y no del mismo tipo para ambos.aquí hay una manera de usar la instrucción SSSE3 pshufb usando su intrínseco Intel, asumiendo que tiene un múltiplo de 4
int
s:fuente
¿Funcionará o será más rápido?
fuente
char
nobyte
.Aquí hay una función que he estado usando, probada y funciona con cualquier tipo de datos básico:
fuente
source
está alineado según sea necesario; sin embargo, si esa suposición no se cumple, el código es UB.EDITAR: Esta función solo intercambia el endianness de las palabras alineadas de 16 bits. Una función a menudo necesaria para codificaciones UTF-16 / UCS-2. EDITAR FIN.
Si desea cambiar la endiabilidad de un bloque de memoria, puede usar mi enfoque increíblemente rápido. Su matriz de memoria debe tener un tamaño múltiplo de 8.
Este tipo de función es útil para cambiar la endiabilidad de los archivos Unicode UCS-2 / UTF-16.
fuente
t know if it
tan rápido como las sugerencias pero funciona: github.com/heatblazer/helpers/blob/master/utils.hCHAR_BIT
en lugar de8
es curioso ya0xFF00FF00FF00FF00ULL
que depende deCHAR_BIT == 8
. Tenga en cuenta queLL
no es necesario en la constante.CHAR_BIT
para aumentar la exposición de esa macro. En cuanto al LL, es más una anotación que cualquier otra cosa. También es un hábito que adquirí hace mucho tiempo con los compiladores con errores (pre estándar) que no harían lo correcto.Este fragmento de código puede convertir un pequeño número Endian de 32 bits en un número Big Endian.
fuente
((i>>24)&0xff) | ((i>>8)&0xff00) | ((i&0xff00)<<8) | (i<<24);
puede ser más rápido en algunas plataformas (por ejemplo, reciclar las constantes de máscara AND). Sin embargo, la mayoría de los compiladores harían esto, pero algunos compiladores simples no pueden optimizarlo por usted.Si está ejecutando en un procesador x86 o x86_64, el big endian es nativo. entonces
para valores de 16 bits
para valores de 32 bits
Esta no es la solución más eficiente a menos que el compilador reconozca que se trata de una manipulación a nivel de bytes y genere un código de intercambio de bytes. Pero no depende de ningún truco de diseño de memoria y se puede convertir en una macro con bastante facilidad.
fuente