C # int ke byte []

172

Saya perlu mengonversi satu intke byte[]satu cara melakukannya adalah dengan menggunakannya BitConverter.GetBytes(). Tetapi saya tidak yakin apakah itu cocok dengan spesifikasi berikut:

Integer bertanda XDR adalah datum 32-bit yang mengkodekan integer dalam kisaran [-2147483648,2147483647]. Bilangan bulat diwakili dalam notasi komplemen dua. Bytes paling signifikan dan paling sedikit adalah 0 dan 3, masing-masing. Integer dinyatakan sebagai berikut:

Sumber: RFC1014 3.2

Bagaimana saya bisa melakukan transformasi int ke byte yang akan memenuhi spesifikasi di atas?

Peter
sumber
Itu pertanyaan yang bagus.
ChaosPandion

Jawaban:

217

RFC hanya mencoba untuk mengatakan bahwa integer yang ditandatangani adalah integer 4-byte normal dengan byte yang dipesan dengan cara big-endian.

Sekarang, Anda kemungkinan besar bekerja pada mesin little-endian dan BitConverter.GetBytes()akan memberi Anda yang byte[]terbalik. Jadi Anda bisa mencoba:

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

Untuk kode yang paling portabel, Anda dapat melakukannya seperti ini:

int intValue;
byte[] intBytes = BitConverter.GetBytes(intValue);
if (BitConverter.IsLittleEndian)
    Array.Reverse(intBytes);
byte[] result = intBytes;
paracycle
sumber
7
Atau gunakan ToArray. byte [] hasil = BitConverter.GetBytes (intValue) .Reverse (). ToArray ();
Lars Truijens
mengapa baris terakhir byte[] result = intBytes;? belum intBytesarray yang Anda inginkan?
derHugo
2
@ DerHugo Itu benar, resultberlebihan dalam bagian kode ini. Namun, saya merasa bahwa lebih pedagogis untuk secara eksplisit menunjukkan kepada pembaca apa hasilnya daripada berasumsi bahwa mereka dapat mengetahui bahwa hasilnya terkandung dalam beberapa variabel bernama intBytes. Selain itu, melakukan penugasan itu murah karena tidak menyalin memori atau mengalokasikan memori baru, itu hanya menambah nama baru ke array yang sudah dialokasikan. Jadi mengapa tidak melakukannya?
paracycle
41

Berikut cara lain untuk melakukannya: seperti yang kita ketahui 1x byte = 8x bit dan juga, integer "biasa" (int32) berisi 32 bit (4 byte). Kita dapat menggunakan operator >> untuk menggeser bit ke kanan (>> operator tidak mengubah nilai.)

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]);
Maciek
sumber
1
Penginisialisasi array dan xor (^) dan & 0xFFbit tidak diperlukan.
dtb
6
Ini big-endian, jadi MSB disimpan terlebih dahulu, jadi Anda harus membalikkan indeks Anda.
Marcin Deptuła
7
Bisakah kita menambahkan contoh sebaliknya? (byte kembali ke integer)
jocull
1
Saya menggunakan ini karena kinerja. Jika saya tidak peduli dengan perbedaan kecil ini , saya akan mencari jawaban yang diterima.
Abadi
2
Anda harus membungkus kode itu dalam sebuah uncheckedblok. Saat ini hanya berfungsi jika pemeriksaan integer overflow dinonaktifkan di pengaturan kompiler.
CodesInChaos
25

BitConverter.GetBytes(int) hampir melakukan apa yang Anda inginkan, kecuali endianness salah.

Anda dapat menggunakan metode IPAddress.HostToNetwork untuk menukar byte dalam nilai integer sebelum menggunakan BitConverter.GetBytesatau menggunakan kelas EndianBitConverter Jon Skeet . Kedua metode melakukan hal yang benar (tm) mengenai portabilitas.

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

Ketika saya melihat deskripsi ini, saya punya perasaan, bahwa bilangan bulat xdr ini hanya bilangan bulat "standar" big-endian, tapi itu diungkapkan dengan cara yang paling dikaburkan. Notasi komplemen dua lebih dikenal sebagai U2, dan itulah yang kami gunakan pada prosesor saat ini. Urutan byte menunjukkan bahwa ini adalah notasi big-endian .
Jadi, menjawab pertanyaan Anda, Anda harus membalikkan elemen dalam array Anda (0 <--> 3, 1 <--> 2), karena elemen-elemen tersebut dikodekan dalam little-endian. Hanya untuk memastikan, Anda harus terlebih dahulu memeriksa BitConverter.IsLittleEndianuntuk melihat pada mesin apa yang Anda jalankan.

Marcin Deptuła
sumber
3

Mengapa semua kode ini ada dalam contoh di atas ...

Struct dengan tata letak eksplisit bertindak dua arah dan tidak memiliki hit kinerja.

Pembaruan: Karena ada pertanyaan tentang cara menangani endianness, saya menambahkan antarmuka yang menggambarkan cara abstrak itu. Struktural pelaksana lain dapat menangani kasus sebaliknya

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; 
}
Sten Petrov
sumber
2
Bagaimana Anda menggunakan ini? dan kedua, apakah Anda akan mendapatkan hasil yang sama walaupun Anda menjalankan ini pada 'big-endian' dan 'little-endian'.
Peter
@ Peter, ini pembaruan. Seharusnya masih berkinerja lebih baik daripada shift
Sten Petrov
ya. Pada dasarnya serikat c ++ diimplementasikan sebagai c # structs. Ini sangat cepat dan bagus untuk mengemas dan membongkar semua jenis hal yang tidak cocok dengan solusi masalah bitconverter / endian. IIRC, NAudio menggunakan pendekatan ini untuk efek yang sangat baik.
Craig. Diisi
Ini adalah jawaban terbaik dan agak menyedihkan bahwa ini bukan yang teratas tetapi hanya memberi tahu Anda sesuatu tentang keadaan pemrograman pada tahun 2019
John Evans
1

Cara lain adalah dengan menggunakan BinaryPrimitive seperti itu

byte[] intBytes = BitConverter.GetBytes(123); int actual = BinaryPrimitives.ReadInt32LittleEndian(intBytes);

Denis
sumber
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("]");
        }
    }
}```
Александр Гром
sumber
-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);
}
Valery Rode
sumber
tolong tambahkan lebih banyak penjelasan
Gregor Doroschenko
Terima kasih atas jawabannya, mengapa Anda memilih untuk menulis implementasi baru alih-alih menggunakan stackoverflow.com/a/1318948/58553 ? (apakah ada pro atau kontra dengan solusi Anda)
Peter
Dalam hal ketika proyek perlu dikembangkan dengan tidak hanya satu bahasa, dapat berguna menyadari kesamaan kode antara bahasa dalam situasi ketika ide-ide yang identik harus dilaksanakan. Cara ini dapat membantu mengatasi kesalahan. Yakin menggunakan fungsi 'c #' BitConverter.GetBytes 'dengan' Endian 'memeriksa semua yang diperlukan dalam kebanyakan kasus. Dan lebih dari itu, dalam beberapa situasi dapat terjadi konversi menggunakan tidak hanya ke Int32 (4 byte) atau Int64 (8 byte) tetapi ke jumlah byte lainnya. Terima kasih.
Valery Rode
Ini tidak benar-benar dapat digunakan secara universal sama sekali ... ia selalu mengembalikan array 8-byte, yang membawa banyak pekerjaan ekstra dengan nilai input yang bukan int 64-bit. Secara logis saya ingin array 2-byte ketika mengkonversi Int16.
Nyerguds