C # int đến byte []


172

Tôi cần phải chuyển đổi một intđến một byte[]một cách để làm việc đó là sử dụng BitConverter.GetBytes(). Nhưng tôi không chắc nếu điều đó phù hợp với đặc điểm kỹ thuật sau:

Một số nguyên có chữ ký XDR là một mốc thời gian 32 bit mã hóa một số nguyên trong phạm vi [-2147483648,2147483647]. Số nguyên được biểu diễn trong ký hiệu bổ sung của hai. Các byte quan trọng nhất và ít nhất là 0 và 3, tương ứng. Số nguyên được khai báo như sau:

Nguồn: RFC1014 3.2

Làm thế nào tôi có thể thực hiện một chuyển đổi int thành byte để đáp ứng các đặc điểm kỹ thuật trên?


Đó là một câu hỏi hay.
ChaosPandion

Câu trả lời:


217

RFC chỉ đang cố gắng nói rằng một số nguyên đã ký là một số nguyên 4 byte bình thường với các byte được sắp xếp theo cách thức lớn.

Bây giờ, rất có thể bạn đang làm việc trên một máy cuối nhỏ và BitConverter.GetBytes()sẽ cung cấp cho bạn byte[]đảo ngược. Vì vậy, bạn có thể thử:

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

Tuy nhiên, để mã dễ di chuyển nhất, bạn có thể làm như thế này:

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

7
Hoặc sử dụng ToArray. byte [] result = BitConverter.GetBytes (intValue) .Reverse (). ToArray ();
Lars Truijens

Tại sao dòng cuối cùng byte[] result = intBytes;? không phải intByteslà mảng bạn muốn?
derHugo

2
@derHugo Điều đó đúng, resultlà dư thừa trong đoạn mã này. Tuy nhiên, tôi cảm thấy rằng nó mang tính sư phạm hơn để cho người đọc thấy rõ kết quả là gì hơn là giả định rằng họ có thể nhận ra rằng kết quả được chứa trong một số biến có tên intBytes. Bên cạnh đó, thực hiện gán là rẻ vì nó không sao chép bộ nhớ cũng không phân bổ bộ nhớ mới, nó chỉ thêm một tên mới vào mảng đã được phân bổ. Vậy tại sao không làm điều đó?
paracycl

41

Đây là một cách khác để làm điều đó: vì tất cả chúng ta đều biết 1x byte = 8 bit và cũng vậy, một số nguyên "thông thường" (int32) chứa 32 bit (4 byte). Chúng ta có thể sử dụng toán tử >> để dịch chuyển bit phải (>> toán tử không thay đổi giá trị.)

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
Bộ khởi tạo mảng và xor (^) và & 0xFFbit là không cần thiết.
dtb

6
Đó là endianian lớn, vì vậy MSB được lưu trữ đầu tiên, vì vậy bạn nên đảo ngược các chỉ số của mình.
Marcin Deptuła

7
Chúng ta có thể thêm một ví dụ về việc đi ngược lại? (byte trở lại số nguyên)
jocull

1
Tôi sử dụng điều này vì hiệu suất. Nếu tôi không quan tâm đến sự khác biệt nhỏ này , tôi sẽ đi đến câu trả lời được chấp nhận.
Vô tận

2
Bạn nên bọc mã đó trong một uncheckedkhối. Hiện tại nó chỉ hoạt động nếu kiểm tra tràn số nguyên bị vô hiệu hóa trong cài đặt trình biên dịch.
CodeInChaos ngày

25

BitConverter.GetBytes(int) hầu như làm những gì bạn muốn, ngoại trừ endianness là sai.

Bạn có thể sử dụng phương thức IPAddress.HostToNetwork để trao đổi các byte trong giá trị số nguyên trước khi sử dụng BitConverter.GetByteshoặc sử dụng lớp EndianBitConverter của Jon Skeet . Cả hai phương pháp đều làm đúng (tm) về tính di động.

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

3

Khi tôi nhìn vào mô tả này, tôi có cảm giác rằng số nguyên xdr này chỉ là một số nguyên "tiêu chuẩn" lớn, nhưng nó được thể hiện theo cách khó hiểu nhất. Ký hiệu bổ sung của hai được biết rõ hơn là U2 và đó là những gì chúng ta đang sử dụng trên các bộ xử lý ngày nay. Thứ tự byte chỉ ra rằng đó là một ký hiệu cuối lớn .
Vì vậy, khi trả lời câu hỏi của bạn, bạn nên đảo ngược các phần tử trong mảng của mình (0 <-> 3, 1 <-> 2), vì chúng được mã hóa theo kiểu endian nhỏ. Để chắc chắn, trước tiên bạn nên kiểm tra BitConverter.IsLittleEndianxem bạn đang chạy trên máy nào.


3

Tại sao tất cả các mã này trong các mẫu ở trên ...

Một cấu trúc với bố cục rõ ràng hoạt động cả hai cách và không có hiệu suất nhấn.

Cập nhật: Vì có một câu hỏi về cách đối phó với endianness, tôi đã thêm một giao diện minh họa cách trừu tượng hóa điều đó. Một cấu trúc thực hiện khác có thể giải quyết trường hợp ngược lại

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
Làm thế nào bạn sẽ sử dụng này? và thứ hai là bạn sẽ nhận được kết quả tương tự ngay cả khi bạn chạy nó trên 'big endian' và 'little endian'.
Peter

@Peter đây là một bản cập nhật. Nó vẫn sẽ hoạt động tốt hơn so với ca
Sten Petrov

vâng Về cơ bản, một liên minh c ++ được triển khai dưới dạng c # structs. Điều này là cực nhanh và tốt cho việc đóng gói và giải nén tất cả các loại điều không phù hợp với các giải pháp vấn đề bitconverter / endian. IIRC, NAudio sử dụng phương pháp này để có hiệu quả rất tốt.
Craig.Feied

Đây là câu trả lời hay nhất và thật đáng buồn vì đây không phải là hàng đầu mà chỉ cho bạn biết điều gì đó về tình trạng lập trình năm 2019
John Evans


1

Một cách khác là sử dụng BinaryPrimitive như vậy

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


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

vui lòng thêm lời giải thích
Gregor Doroschenko

Cảm ơn câu trả lời, tại sao bạn lại chọn viết một triển khai mới thay vì sử dụng stackoverflow.com/a/1318948/58553 ? (có bất kỳ ủng hộ hay khuyết điểm nào với giải pháp của bạn không)
Peter

Trong trường hợp khi dự án cần được phát triển với không chỉ một ngôn ngữ, có thể hữu ích nhận ra sự tương tự mã giữa các ngôn ngữ trong tình huống khi các ý tưởng giống hệt nhau phải được thực hiện. Cách này có thể giúp đỡ với những sai lầm bắt. Chắc chắn sử dụng chức năng 'c #' 'BitConverter.GetBytes' với 'Endian' kiểm tra tất cả những gì cần thiết trong hầu hết các trường hợp. Và hơn nữa, trong một số trường hợp có thể xảy ra, sử dụng chuyển đổi không chỉ sang Int32 (4 byte) hoặc Int64 (8 byte) mà còn cho số byte khác. Cảm ơn.
Valery Rode

Điều này hoàn toàn không thể sử dụng được ... nó luôn trả về một mảng 8 byte, mang lại rất nhiều công việc bổ sung với các giá trị đầu vào không phải là int 64 bit. Tôi muốn logic một mảng 2 byte khi chuyển đổi một Int16.
Nyerguds
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.