C#intからbyte []


172

私はそれを使用intするbyte[]1つの方法に変換する必要がありますBitConverter.GetBytes()。しかし、それが次の仕様と一致するかどうかは不明です。

XDR符号付き整数は、[-2147483648,2147483647]の範囲の整数をエンコードする32ビットのデータです。整数は2の補数表記で表されます。最上位バイトと最下位バイトは、それぞれ0と3です。整数は次のように宣言されます。

ソース: RFC1014 3.2

上記の仕様を満たすintからbyteへの変換をどのように実行できますか?


それは良い質問です。
ChaosPandion 2009

回答:


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、2011年

なぜ最後の行byte[] result = intBytes;intBytes必要な配列はまだありませんか?
derHugo

2
@derHugo正解resultです。このコードでは冗長です。ただし、結果がという名前の変数に含まれていることを理解できると想定するよりも、結果を明確に読者に示す方が教育的であると感じましたintBytes。その上、メモリをコピーしたり新しいメモリを割り当てたりしないので、割り当てを行うことは安価です。すでに割り当てられている配列に新しい名前を追加するだけです。それで、なぜそれをしないのですか?
パラ

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 2009

6
これはビッグエンディアンなので、MSBが最初に格納されるため、インデックスを逆にする必要があります。
MarcinDeptuła、2009

7
逆の例を追加できますか?(バイトから整数に戻す)
jocull

1
パフォーマンスの理由でこれを使用します。この小さな違いが気にならなければ、受け入れられた答えを探します。
タイムレス

2
そのコードをuncheckedブロックでラップする必要があります。現在、コンパイラ設定で整数オーバーフローチェックが無効になっている場合にのみ機能します。
CodesInChaos 2018

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
これをどのように使用しますか?次に、これを「ビッグエンディアン」と「リトルエンディアン」で実行しても、同じ結果が得られます。
Peter

@ピーターはここに更新です。それでもシフトよりも優れたパフォーマンスを発揮するはずです
Sten Petrov

うん。基本的に、c#構造体として実装されたc ++共用体。これは超高速であり、ビットコンバーター/エンディアン問題の解決策にうまく適合しないあらゆる種類の物をパックおよびアンパックするのに適しています。IIRC、NAudioはこのアプローチを使用して非常に優れた効果を発揮します。
クレイグ。

これは最良の答えです。これがトップではないのはちょっと悲しいですが、2019年のプログラミングの状態について何かを伝えています
John Evans


1

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

さらに説明を追加してください
グレゴール・ドロシェンコ

答えてくれてありがとう。なぜ、stackoverflow.com / a / 1318948/58553を使用する代わりに、新しい実装を作成することにしたのですか。(あなたの解決策には賛否両論があります)
ピーター

プロジェクトを1つの言語だけで開発する必要がない場合、同じアイデアを実装する必要がある状況で、言語間のコードの類似性を実現するのに役立ちます。この方法は、間違いを見つけるのに役立ちます。確かに、 'c#'関数 'BitConverter.GetBytes'を 'Endian'と共に使用して、ほとんどの場合に必要なものすべてをチェックします。さらに、状況によっては、Int32(4バイト)またはInt64(8バイト)だけでなく、他のバイト数への変換を使用することもありました。ありがとう。
Valery Rode、

これはまったく普遍的に使用できるわけではありません...それは常に8バイトの配列を返します。これは64ビットの整数ではない入力値で多くの追加作業をもたらします。を変換するときに論理的に2バイトの配列が必要ですInt16
Nyerguds
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.