C # int in byte []


172

Ho bisogno di convertire un intin un byte[]modo per farlo è quello di utilizzare BitConverter.GetBytes(). Ma non sono sicuro che corrisponda alle seguenti specifiche:

Un numero intero con segno XDR è un dato a 32 bit che codifica un numero intero nell'intervallo [-2147483648,2147483647]. L'intero è rappresentato nella notazione del complemento a due. I byte più e meno significativi sono rispettivamente 0 e 3. I numeri interi sono dichiarati come segue:

Fonte: RFC1014 3.2

Come potrei fare un int alla trasformazione dei byte che soddisferebbe le specifiche sopra?


Questa è una buona domanda
ChaosPandion,

Risposte:


217

La RFC sta solo cercando di dire che un intero con segno è un normale numero intero a 4 byte con byte ordinati in modo big-endian.

Ora, molto probabilmente stai lavorando su una macchina little-endian e BitConverter.GetBytes()ti darà il byte[]contrario. Quindi potresti provare:

int intValue;
byte[] intBytes = BitConverter.GetBytes(intValue);
Array.Reverse(intBytes);
byte[] result = intBytes;

Per rendere il codice più portatile, tuttavia, puoi farlo in questo modo:

int intValue;
byte[] intBytes = BitConverter.GetBytes(intValue);
if (BitConverter.IsLittleEndian)
    Array.Reverse(intBytes);
byte[] result = intBytes;

7
Oppure usa ToArray. byte [] risultato = BitConverter.GetBytes (intValue) .Reverse (). ToArray ();
Lars Truijens,

perché l'ultima riga byte[] result = intBytes;? non è intBytesgià l'array che desideri?
derHugo,

2
@derHugo È corretto, resultè ridondante in questo pezzo di codice. Tuttavia, ho ritenuto che fosse più pedagogico mostrare esplicitamente al lettore quale fosse il risultato piuttosto che supporre che potessero capire che il risultato è contenuto in una variabile denominata intBytes. Inoltre, l'assegnazione è economica poiché non copia la memoria né alloca nuova memoria, aggiunge semplicemente un nuovo nome all'array già allocato. Quindi perché non farlo?
paraciclo

41

Ecco un altro modo per farlo: come tutti sappiamo 1x byte = 8x bit e inoltre, un intero "regolare" (int32) contiene 32 bit (4 byte). Possiamo usare l'operatore >> per spostare i bit a destra (l'operatore >> non cambia valore).

int intValue = 566;

byte[] bytes = new byte[4];

bytes[0] = (byte)(intValue >> 24);
bytes[1] = (byte)(intValue >> 16);
bytes[2] = (byte)(intValue >> 8);
bytes[3] = (byte)intValue;

Console.WriteLine("{0} breaks down to : {1} {2} {3} {4}",
    intValue, bytes[0], bytes[1], bytes[2], bytes[3]);

1
L'inizializzatore di array e xor (^) e i & 0xFFbit non sono necessari.
dtb,

6
È big-endian, quindi MSB viene memorizzato per primo, quindi dovresti invertire i tuoi indici.
Marcin Deptuła,

7
Possiamo aggiungere un esempio di come andare al contrario? (byte torna al numero intero)
giocate

1
Lo uso a causa delle prestazioni. Se non mi interessa questa piccola differenza, cercherò la risposta accettata.
Senza tempo,

2
Dovresti racchiudere quel codice in un uncheckedblocco. Attualmente funziona solo se il controllo di overflow dei numeri interi è disabilitato nelle impostazioni del compilatore.
Codici InChaos

25

BitConverter.GetBytes(int) fa quasi quello che vuoi, tranne che l'endianità è sbagliata.

È possibile utilizzare il metodo IPAddress.HostToNetwork per scambiare i byte all'interno del valore intero prima di utilizzare BitConverter.GetByteso utilizzare la classe EndianBitConverter di Jon Skeet . Entrambi i metodi fanno la cosa giusta (tm) per quanto riguarda la portabilità.

int value;
byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value));

3

Quando guardo questa descrizione, ho la sensazione che questo intero xdr sia solo un intero "standard" big-endian, ma è espresso nel modo più offuscato. La notazione del complemento a due è meglio conosciuta come U2, ed è ciò che stiamo usando sui processori di oggi. L'ordine dei byte indica che si tratta di una notazione big-endian .
Quindi, per rispondere alla tua domanda, dovresti invertire gli elementi nell'array (0 <--> 3, 1 <--> 2), poiché sono codificati in little-endian. Solo per essere sicuri, dovresti prima controllare BitConverter.IsLittleEndianper vedere su quale macchina stai eseguendo.


3

Perché tutto questo codice negli esempi sopra ...

Una struttura con layout esplicito agisce in entrambi i modi e non ha alcun impatto sulle prestazioni.

Aggiornamento: poiché c'è una domanda su come gestire l'endianness, ho aggiunto un'interfaccia che illustra come astrarre ciò. Un'altra struttura attuativa può occuparsi del caso opposto

public interface IIntToByte
{
    Int32 Int { get; set;}

    byte B0 { get; }
    byte B1 { get; }
    byte B2 { get; }
    byte B3 { get; }
}

[StructLayout(LayoutKind.Explicit)]
public struct IntToByteLE : UserQuery.IIntToByte
{
    [FieldOffset(0)]
    public Int32 IntVal;

    [FieldOffset(0)]
    public byte b0;
    [FieldOffset(1)]
    public byte b1;
    [FieldOffset(2)]
    public byte b2;
    [FieldOffset(3)]
    public byte b3;

    public Int32 Int {
        get{ return IntVal; }
        set{ IntVal = value;}
    }

    public byte B0 => b0;
    public byte B1 => b1;
    public byte B2 => b2;
    public byte B3 => b3; 
}

2
Come lo useresti? e in secondo luogo otterresti lo stesso risultato anche se lo esegui su "big-endian" e su "little-endian".
Peter

@Peter ecco un aggiornamento. Dovrebbe comunque funzionare meglio dei turni
Sten Petrov,

Sì. Fondamentalmente un'unione c ++ implementata come strutture c #. Questo è super-veloce ed è buono per imballare e disimballare tutti i tipi di cose che non si adattano perfettamente alle soluzioni problematiche bitconverter / endian. IIRC, NAudio utilizza questo approccio con ottimi risultati.
Craig

Questa è la risposta migliore ed è un po 'triste che questo non sia il massimo, ma ti dice solo qualcosa sullo stato della programmazione nel 2019
John Evans,



0
using static System.Console;

namespace IntToBits
{
    class Program
    {
        static void Main()
        {
            while (true)
            {
                string s = Console.ReadLine();
                Clear();
                uint i;
                bool b = UInt32.TryParse(s, out i);
                if (b) IntPrinter(i);
            }
        }

        static void IntPrinter(uint i)
        {
            int[] iarr = new int [32];
            Write("[");
            for (int j = 0; j < 32; j++)
            {
                uint tmp = i & (uint)Math.Pow(2, j);

                iarr[j] = (int)(tmp >> j);
            }
            for (int j = 32; j > 0; j--)
            {
                if(j%8==0 && j != 32)Write("|");
                if(j%4==0 && j%8 !=0) Write("'");
                Write(iarr[j-1]);
            }
            WriteLine("]");
        }
    }
}```

-1
byte[] Take_Byte_Arr_From_Int(Int64 Source_Num)
{
   Int64 Int64_Num = Source_Num;
   byte Byte_Num;
   byte[] Byte_Arr = new byte[8];
   for (int i = 0; i < 8; i++)
   {
      if (Source_Num > 255)
      {
         Int64_Num = Source_Num / 256;
         Byte_Num = (byte)(Source_Num - Int64_Num * 256);
      }
      else
      {
         Byte_Num = (byte)Int64_Num;
         Int64_Num = 0;
      }
      Byte_Arr[i] = Byte_Num;
      Source_Num = Int64_Num;
   }
   return (Byte_Arr);
}

si prega di aggiungere ulteriori spiegazioni
Gregor Doroschenko

Grazie per la risposta, perché hai scelto di scrivere una nuova implementazione invece di utilizzare stackoverflow.com/a/1318948/58553 ? (ci sono pro o contro con la tua soluzione)
Peter,

Nel caso in cui il progetto debba essere sviluppato con una sola lingua, può essere utile realizzare la somiglianza del codice tra le lingue nella situazione in cui devono essere implementate idee identiche. In questo modo può essere utile individuare errori. Sicuramente usando la funzione 'c #' BitConverter.GetBytes 'con' Endian 'controlla che tutto ciò che serve nella maggior parte dei casi. Inoltre, in alcune situazioni può accadere che usi la conversione non solo in Int32 (4 byte) o Int64 (8 byte) ma in un altro numero di byte. Grazie.
Valery Rode,

Questo non è davvero universalmente utilizzabile a tutti ... restituisce sempre un array di 8 byte, il che porta molto lavoro extra con valori di input che non sono in 64 bit. Vorrei logicamente un array a 2 byte durante la conversione di un Int16.
Nyerguds,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.