2010-11-14 22 views
42

pensé .net tenido algún tipo de método de conversión fácil de usar para convertir un entero en una matriz de bytes? Hice una búsqueda rápida y todas las soluciones son un poco máscaras/cambios de un byte a la vez, como "los buenos días". ¿No hay un método ToByteArray() en alguna parte?Int matriz de bytes a

Respuesta

69
byte[] bytes = BitConverter.GetBytes(i); 

aunque también se nota que usted puede ser que desee comprobar BitConverter.IsLittleEndian para ver qué forma de evitar eso va a aparecer!

Tenga en cuenta que si usted está haciendo esto en repetidas ocasiones es posible que desee evitar todas esas asignaciones de matriz de corta vida escribiendo usted mismo, ya sea a través de operaciones de desplazamiento (>>/<<), o mediante el uso unsafe código. Las operaciones de desplazamiento también tienen la ventaja de que no se ven afectadas por orden de bits de su plataforma; usted siempre obtenga los bytes en el orden en que los espera.

+2

1: Para mayor claridad, me reemplace en "[...] en el orden en que se espera" con "big-endian". – Ani

+0

'¿Por qué BitConverter.GetBytes (250)' 'retorno [250,0,0,0]' y no '[250]'? 'Byte.MaxValue == 255', ¿verdad? –

+0

@Tobi porque está llamando a GetBytes (int) - entonces: 4 bytes, y su CPU es little-endian. No habría ningún propósito en un método GetBytes (byte). –

28

la respuesta de Marc es por supuesto la respuesta correcta. Pero desde que mencionó los operadores de turno y el código inseguro como una alternativa. Me gustaría compartir una alternativa menos común. Usar una estructura con diseño Explicit. Esto es similar en principio a C/C++ union.

Aquí hay un ejemplo de una estructura que se puede utilizar para llegar a los bytes componentes del tipo de datos Int32 y lo bueno es que es bidireccional, puede manipular los valores de bytes y ver el efecto en el Int. .

using System.Runtime.InteropServices; 

    [StructLayout(LayoutKind.Explicit)] 
    struct Int32Converter 
    { 
    [FieldOffset(0)] public int Value; 
    [FieldOffset(0)] public byte Byte1; 
    [FieldOffset(1)] public byte Byte2; 
    [FieldOffset(2)] public byte Byte3; 
    [FieldOffset(3)] public byte Byte4; 

    public Int32Converter(int value) 
    { 
     Byte1 = Byte2 = Byte3 = Byte4 = 0; 
     Value = value; 
    } 

    public static implicit operator Int32(Int32Converter value) 
    { 
     return value.Value; 
    } 

    public static implicit operator Int32Converter(int value) 
    { 
     return new Int32Converter(value); 
    } 
    } 

Lo anterior ahora se puede utilizar como sigue

Int32Converter i32 = 256; 
Console.WriteLine(i32.Byte1); 
Console.WriteLine(i32.Byte2); 
Console.WriteLine(i32.Byte3); 
Console.WriteLine(i32.Byte4); 

i32.Byte2 = 2; 
Console.WriteLine(i32.Value); 

Por supuesto la policía inmutabilidad pueden no estar entusiasmado con la última posibilidad :)

+0

+ 1: Este es un buen enfoque. Si le preocupa la policía de inmutabilidad, puede hacer que los campos sean privados y exponerlos con propiedades solo para obtener. – Ani

+0

@Ani, gracias. Es una buena idea hacer que los miembros de 'byte' sean privados y crear propiedades solo para obtener. –

+0

La declaración (es) 'Byte1 = Byte2 = Byte3 = Byte4 = 0;' son redundantes ya que la posterior asignación de Valor los sobrescribe. Este es precisamente el tipo de alias que dirige a los escritores optimizadores del compilador. La unión es elegante ya que colapsa las escrituras múltiples en una sola a través del canal de memoria. El uso de struct también evita la asignación de matriz para casos extremadamente frecuentes. – Pekka

2

Esto puede ser OT pero si usted está serializando una gran cantidad de tipos primitivos o estructuras POD, Google Protocol Buffers for .Net pueden serle útiles. Esto aborda el problema de endianness @Marc mencionado anteriormente, entre otras características útiles.

0

La mayoría de las respuestas aquí son o bien 'inseguros" o no segura LittleEndian. BitConverter no es LittleEndian seguro. lo tanto sobre la base de un ejemplo en el here (ver el mensaje por PZahra) hice una versión segura LittleEndian simplemente mediante la lectura de la matriz de bytes a la inversa cuando == BitConverter.IsLittleEndian cierto

void Main(){  
    Console.WriteLine(BitConverter.IsLittleEndian); 
    byte[] bytes = BitConverter.GetBytes(0xdcbaabcdfffe1608); 
    //Console.WriteLine(bytes); 
    string hexStr = ByteArrayToHex(bytes); 
    Console.WriteLine(hexStr); 
} 

public static string ByteArrayToHex(byte[] data) 
{ 
    char[] c = new char[data.Length * 2]; 
    byte b; 
    if(BitConverter.IsLittleEndian) 
    { 
     //read the byte array in reverse 
     for (int y = data.Length -1, x = 0; y >= 0; --y, ++x) 
     { 
      b = ((byte)(data[y] >> 4)); 
      c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
      b = ((byte)(data[y] & 0xF)); 
      c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
     }    
    } 
    else 
    { 
     for (int y = 0, x = 0; y < data.Length; ++y, ++x) 
     { 
      b = ((byte)(data[y] >> 4)); 
      c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
      b = ((byte)(data[y] & 0xF)); 
      c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30); 
     } 
    } 
    return String.Concat("0x",new string(c)); 
} 

devuelve la siguiente:.

True 
0xDCBAABCDFFFE1608 

que es el hexadecimal exacto en que entró en la matriz de bytes

+0

No comienza desde un int, sin embargo. Sin mencionar, es mucho más lógico hacer esa verificación de endianness en _read_ para estar seguro de cómo son tus datos en la matriz. – Nyerguds

Cuestiones relacionadas