2010-11-14 22 views
42

Pensavo che .net avesse un qualche tipo di semplice metodo di conversione da utilizzare per convertire un int in un array di byte? Ho fatto una rapida ricerca e tutte le soluzioni sono bit masking/shifting di un byte alla volta, come "the good ol days". Non c'è un metodo ToByteArray() da qualche parte?Int a byte array

risposta

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

anche se nota anche che si potrebbe voler controllare BitConverter.IsLittleEndian per vedere quale modo per aggirare questo sta per apparire!

Si noti che se si sta facendo questo ripetutamente si potrebbe voler evitare tutte quelle assegnazioni di array di breve durata scrivendo da soli tramite sia le operazioni di spostamento (>>/<<), oppure utilizzando unsafe codice. Le operazioni Shift hanno il vantaggio di non essere influenzate dall'endianness della tua piattaforma; Si sempre ottenere i byte nell'ordine in cui li si aspetta.

+2

+1: Per chiarezza, vorrei sostituire "[...] nell'ordine in cui li aspetti" con "big-endian". – Ani

+0

Perché 'BitConverter.GetBytes (250)' restituisce '[250,0,0,0]', e non '[250]'? 'Byte.MaxValue == 255', giusto? –

+0

@Tobi perché stai chiamando GetBytes (int) - così: 4 byte e la tua CPU è little-endian. Non ci sarebbe scopo in un metodo GetBytes (byte). –

28

La risposta di Marc è ovviamente la risposta giusta. Ma dal momento che ha menzionato gli operatori di turno e il codice non sicuro come alternativa. Mi piacerebbe condividere un'alternativa meno comune. Utilizzo di una struttura con il layout Explicit. Questo è simile in linea di principio a un C/C++ union.

Ecco un esempio di una struttura che può essere utilizzata per ottenere i byte componente del tipo di dati Int32 e la cosa bella è che è a due vie, è possibile manipolare i valori di byte e vedere l'effetto sull'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); 
    } 
    } 

Quanto sopra può ora essere utilizzato come segue

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); 

Naturalmente la polizia immutabilità potrebbero non essere entusiasti l'ultimo possiblity :)

+0

+ 1: questo è un buon approccio Se sei preoccupato per la polizia dell'immutabilità, puoi rendere i campi privati ​​ed esporli con proprietà get-only. – Ani

+0

@Ani, grazie, è una buona idea rendere privati ​​i membri 'byte' e creare proprietà get-only. –

+0

La/e dichiarazione/i 'Byte1 = Byte2 = Byte3 = Byte4 = 0;' sono ridondanti mentre la successiva assegnazione di valore li sovrascrive. Questo è esattamente il tipo di aliasing che fa impazzire gli scrittori dell'ottimizzatore del compilatore. L'unione è elegante in quanto collassa le scritture multiple in una sola attraverso il canale di memoria. L'uso della struct evita anche l'allocazione dell'array per casi estremamente frequenti. – Pekka

2

Questo può essere OT, ma se siete alla serializzazione molti tipi primitivi o strutture POD, Google Protocol Buffers for .Net potrebbero esserti utili. Questo risolve il problema di endianness @Marc sollevato sopra, tra le altre utili funzioni.

0

La maggior parte delle risposte qui sono o 'non sicuro" o non è sicuro LittleEndian. BitConverter non è LittleEndian sicura. Così costruire su un esempio in here (vedi il post da PZahra) ho fatto una versione sicura LittleEndian semplicemente leggendo il byte all'indietro quando == BitConverter.IsLittleEndian vero

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

e restituita.

True 
0xDCBAABCDFFFE1608 

che è l'esagono esatto che è andato in byte

+0

Non parte da un int, però. Per non parlare del fatto che è molto più logico eseguire il controllo endianness su _read_ in modo da essere sicuri di cosa siano i dati nell'array. – Nyerguds