2008-10-20 41 views
52

En la documentación de hardware que nos permite controlar que a través de UDP/IP, I encontraron la siguiente fragmento:C# little endian o big endian?

En este protocolo de comunicación, DWORD es una datos de 4 bytes, WORD es un datos de 2 bytes, BYTE es un dato de un solo byte. El formato de almacenamiento es poco endian, es decir, los datos de 4 bytes (32 bits) se almacenan como: d7-d0, d15-d8, d23-d16, d31-d24; los datos de doble byte (16bits) se almacenan como: d7-d0, d15-d8.

Me pregunto cómo se traduce esto en C#? ¿Tengo que convertir cosas antes de enviarlas? Por ejemplo, si deseo enviar un entero de 32 bits o una cadena de 4 caracteres?

Respuesta

66

C# en sí mismo no define el endianness. Sin embargo, cuando convierte a bytes, está haciendo una elección. La clase BitConverter tiene un campo IsLittleEndian para indicarle cómo se comportará, pero no da la opción. Lo mismo aplica para BinaryReader/BinaryWriter.

Mi biblioteca MiscUtil tiene una clase EndianBitConverter que le permite definir el endianness; hay equivalentes similares para BinaryReader/Writer. Ninguna guía de uso en línea me temo, pero son triviales :)

(EndianBitConverter también tiene una funcionalidad que no está presente en el BitConverter normal, que consiste en realizar conversiones in situ en una matriz de bytes .)

+2

Recuerde también que en C# es posible copiar valores directamente, p. * ptr = valor; en ese caso, debería preocuparse por el orden de bytes de las arquitecturas informáticas. – markmnl

10

Re little-endian, la respuesta corta (para hacer lo que necesito hacer) es "probablemente no, pero depende de su hardware". Puede consultar con:

bool le = BitConverter.IsLittleEndian; 

Dependiendo de lo que diga, es posible que desee invertir partes de sus búferes. Alternativamente, Jon Skeet tiene convertidores Endian específicos here (busque EndianBitConverter).

Tenga en cuenta que los itaniums (por ejemplo) son big-endian. La mayoría de los intels son pequeños endian.

¿Cuál es el UDP/IP específico ...?

+0

... ¿Hay alguien utilizando .NET en Itanium? – SingleNegationElimination

+0

hmm. Lo que la investigación básica que acabo de hacer parece sugerir que Windows siempre es poco endian (Itanium puede soportar endianismos). Así que BitConverter.IsLittleEndian parece que * siempre * va a volver verdadero, a menos que esté ejecutando algo similar a Mono en un linux big-endian en itanium. Ver http://blogs.msdn.com/larryosterman/archive/2005/06/07/426334.aspx – piers7

+0

Uno de los comentarios sugiere que xna en xbox puede ser big-endian; No he verificado: http://blogs.msdn.com/larryosterman/archive/2005/06/07/426334.aspx#426591 –

3

Necesita conocer el orden de los bytes de la red y la permanencia de la CPU.

Normalmente para las comunicaciones TCP/UDP, siempre convierte datos en orden de bytes de red utilizando la función htons (y ntohs, y sus funciones relacionadas).

Normalmente, el orden de la red es big-endian, pero en este caso (¡por alguna razón!) Las comunicaciones son poco endian, por lo que esas funciones no son muy útiles. Esto es importante ya que no puede suponer que las comunicaciones UDP que han implementado siguen otros estándares, sino que también dificulta la vida si tiene una arquitectura big-endian ya que no puede envolver todo con htons como debería :-(

sin embargo, si usted está viniendo de una arquitectura Intel x86, entonces ya estás ascendente hacia la izquierda, por lo que sólo envía los datos sin necesidad de conversión.

41

también puede utilizar

IPAddress.NetworkToHostOrder(...) 

Para short, int o largo

0

Si va a analizar y el rendimiento no es crítico, tenga en cuenta este código muy simple:

private static byte[] NetworkToHostOrder (byte[] array, int offset, int length) 
{ 
    return array.Skip (offset).Take (length).Reverse().ToArray(); 
} 

int foo = BitConverter.ToInt64 (NetworkToHostOrder (queue, 14, 8), 0); 
0

estoy jugando un poco con los datos empaquetados en UDP Multicast y necesitaba algo para cambiar el orden de los octetos uint16 ya que me di cuenta un error en la cabecera de paquete (Wireshark), por lo que hizo esta:

private UInt16 swapOctetsUInt16(UInt16 toSwap) 
    { 
     Int32 tmp = 0; 
     tmp = toSwap >> 8; 
     tmp = tmp | ((toSwap & 0xff) << 8); 
     return (UInt16) tmp; 
    } 

en caso de UInt32,

private UInt32 swapOctetsUInt32(UInt32 toSwap) 
    { 
     UInt32 tmp = 0; 
     tmp = toSwap >> 24; 
     tmp = tmp | ((toSwap & 0xff0000) >> 8); 
     tmp = tmp | ((toSwap & 0xff00) << 8); 
     tmp = tmp | ((toSwap & 0xff) << 24); 
     return tmp; 
    } 

Esto es sólo para las pruebas

private void testSwap() { 
     UInt16 tmp1 = 0x0a0b; 
     UInt32 tmp2 = 0x0a0b0c0d; 
     SoapHexBinary shb1 = new SoapHexBinary(BitConverter.GetBytes(tmp1)); 
     SoapHexBinary shb2 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt16(tmp1))); 
     Debug.WriteLine("{0}", shb1.ToString()); 
     Debug.WriteLine("{0}", shb2.ToString()); 
     SoapHexBinary shb3 = new SoapHexBinary(BitConverter.GetBytes(tmp2)); 
     SoapHexBinary shb4 = new SoapHexBinary(BitConverter.GetBytes(swapOctetsUInt32(tmp2))); 
     Debug.WriteLine("{0}", shb3.ToString()); 
     Debug.WriteLine("{0}", shb4.ToString()); 
    } 

a partir del cual la producción fue la siguiente:

0B0A: {0} 
    0A0B: {0} 
    0D0C0B0A: {0} 
    0A0B0C0D: {0} 
Cuestiones relacionadas