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.