C # int to 바이트 []


172

int를 사용하는 byte[]한 가지 방법 으로 변환해야 합니다 BitConverter.GetBytes(). 그러나 그것이 다음 사양과 일치하는지 확실하지 않습니다.

XDR 부호있는 정수는 [-2147483648,2147483647] 범위의 정수를 인코딩하는 32 비트 데이텀입니다. 정수는 2의 보수 표기법으로 표시됩니다. 최상위 바이트와 최하위 바이트는 각각 0과 3입니다. 정수는 다음과 같이 선언됩니다.

출처: RFC1014 3.2

위의 사양을 충족시키는 int to byte 변환을 어떻게 수행 할 수 있습니까?


좋은 질문입니다.
ChaosPandion

답변:


217

RFC는 부호있는 정수가 빅 엔디안 방식으로 바이트가 정렬 된 일반적인 4 바이트 정수라고 말하려고합니다.

이제, 당신은 아마도 리틀 엔디안 머신에서 작업하고 있고 반대로 BitConverter.GetBytes()당신에게 줄 byte[]것이다. 그래서 당신은 시도 할 수 있습니다 :

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

그러나 코드를 가장 이식하기 쉽게하려면 다음과 같이하면됩니다.

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

7
또는 ToArray를 사용하십시오. byte [] result = BitConverter.GetBytes (intValue) .Reverse (). ToArray ();
Lars Truijens

왜 마지막 줄 byte[] result = intBytes;? 없는 intBytes이미 당신이 원하는 배열?
derHugo

2
@derHugo 맞습니다 result.이 코드는 중복됩니다. 그러나 결과가라는 일부 변수에 포함되어 있다고 생각할 수 있다고 가정하는 것보다 독자에게 결과가 무엇인지 명시 적으로 보여주는 것이 교육적이라고 생각했습니다 intBytes. 또한 메모리를 복사하거나 새 메모리를 할당하지 않기 때문에 할당을 수행하는 것이 저렴합니다. 이미 할당 된 배열에 새 이름을 추가하기 만합니다. 왜 안 해?
paracycle

41

여기에는 또 다른 방법이 있습니다. 모두 1x 바이트 = 8x 비트를 알고 있고 "정규"정수 (int32)에는 32 비트 (4 바이트)가 들어 있습니다. >> 연산자를 사용하여 비트를 오른쪽으로 이동할 수 있습니다 (>> 연산자는 값을 변경하지 않습니다).

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
배열 이니셜 라이저와 xor (^) 및 & 0xFF비트는 필요하지 않습니다.
dtb

6
빅 엔디안이므로 MSB가 먼저 저장되므로 인덱스를 반대로해야합니다.
Marcin Deptuła

7
반대 방향으로가는 예를 추가 할 수 있습니까? (정수로 바이트)
jocull

1
나는 성능 때문에 이것을 사용합니다. 이 작은 차이에 관심이 없다면 받아 들여질 것입니다.
타임리스

2
해당 코드를 unchecked블록으로 묶어야합니다. 현재 컴파일러 설정에서 정수 오버플로 검사가 비활성화 된 경우에만 작동합니다.
코드 InChaos

25

BitConverter.GetBytes(int) 엔디안이 잘못되었다는 것을 제외하고는 원하는 것을 거의 수행합니다.

Jon Skeet의 EndianBitConverter 클래스 를 사용 하거나 사용 하기 전에 IPAddress.HostToNetwork 메소드를 사용하여 정수 값 내의 바이트를 교환 할 수 있습니다 . 두 가지 방법 모두 이식성과 관련하여 올바른 일을합니다.BitConverter.GetBytes

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

3

이 설명을 볼 때이 xdr 정수는 단지 빅 엔디안 "표준"정수이지만 가장 난독 한 방식으로 표현된다는 느낌이 듭니다. 2의 보수 표기법 은 U2로 더 잘 알려져 있으며 오늘날의 프로세서에서 사용하고 있습니다. 바이트 순서는 빅 엔디안 표기법 임을 나타냅니다 .
따라서 질문에 대답하면 리틀 엔디안으로 인코딩되므로 배열 (0 <-> 3, 1 <-> 2)의 요소를 역으로 사용해야합니다. 확인 BitConverter.IsLittleEndian하려면 먼저 어떤 컴퓨터에서 실행 중인지 확인해야합니다 .


3

위의 샘플 에서이 코드가 모두 왜 ...

명시적인 레이아웃을 가진 구조체는 두 가지 방식으로 작동하며 성능 저하가 없습니다.

업데이트 : 엔디안 처리 방법에 대한 질문이 있으므로 추상화 방법을 설명하는 인터페이스를 추가했습니다. 다른 구현 구조체는 반대의 경우를 다룰 수 있습니다

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
이것을 어떻게 사용 하시겠습니까? 두 번째로 'big-endian'과 'little-endian'에서 동일한 결과를 얻을 수 있습니다.
Peter

@Peter는 여기 업데이트입니다. 아직 변화보다 더 수행해야합니다
스텐 페트로프에게

예. 기본적으로 c ++ 구조체로 구현 된 c ++ 공용체 이것은 초고속이며 비트 변환기 / 엔디안 문제 솔루션에 잘 맞지 않는 모든 종류의 포장 및 포장 풀기에 좋습니다. IIRC, NAudio는이 접근 방식을 사용하여 매우 효과적입니다.
Craig.

이것은 최고의 답변이며 이것이 최고가 아니라 2019 년 프로그래밍 상태에 대해 알려주는 것이 다소 슬픈 일입니다.
John Evans


1

다른 방법은 BinaryPrimitives 를 사용하는 것입니다.

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

더 설명을 추가하십시오
그레고르 Doroschenko에게

답변 주셔서 감사합니다. 왜 stackoverflow.com/a/1318948/58553 대신 새 구현을 작성하도록 선택 했 습니까? (솔루션에 찬반 양론이
Peter

하나의 언어로만 프로젝트를 개발해야하는 경우 동일한 아이디어를 구현해야하는 상황에서 언어 간의 코드 유사성을 실현하는 것이 유용 할 수 있습니다. 이 방법은 실수를 잡는 데 도움이 될 수 있습니다. 'Endian'과 함께 'c #'함수 'BitConverter.GetBytes'를 사용하여 대부분의 경우 필요한 모든 것을 확인하십시오. 또한 상황에 따라 Int32 (4 바이트) 또는 Int64 (8 바이트)뿐만 아니라 다른 바이트 수로의 변환을 사용할 수도 있습니다. 감사.
Valery Rode

이것은 실제로 보편적으로 사용 가능한 것은 아닙니다 ... 항상 8 바이트 배열을 반환하므로 64 비트 정수가 아닌 입력 값으로 많은 추가 작업을 수행합니다. 을 변환 할 때 논리적으로 2 바이트 배열을 원합니다 Int16.
Nyerguds
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.