HOWTO · Csharp

C# で Int を Byte に変換する

この記事では、C# で Int を Byte に変換するためのいくつかの異なる手法を見ていきます。

このページの内容

C# では、何を保存するかによって適切な変換方法が異なります。byte は 0~255 の符号なしの値を1つ保持します。byte[] は、より大きな値を表すバイト列を保持します。結果を1バイトにする場合は Convert.ToByte を使い、int のバイナリ表現が必要な場合は BitConverter.GetBytes またはストリームを使います。ファイル形式やネットワーク形式では、必要なバイト順も明示的に選んでください。

byte と byte[] のどちらを使うか

int は符号付き32ビット整数ですが、byte は符号なし8ビット整数1つです。そのため、int を byte に変換できるのは、値が0~255の範囲にある場合だけです。一方、byte[] なら int の4バイトすべてを保持できます。別のシステムが数値を復元するときは、バイトの並び順が重要です。

小さなカウント値やチャンネル値など、1バイトに収まると分かっている値には、単一の byte への変換を選びます。シリアル化、バイナリプロトコル、またはバイト列を要求するAPIには配列を使います。数値を十進数の文字列にしてからエンコードするのは別の処理です。整数123のバイナリ表現ではなく、1、2、3 のような文字を保存します。

値を Convert.ToByte で byte に変換する

Convert.ToByte が返すのは、単一の byte です。文字列を受け取るオーバーロードは十進数の数値文字列を解析し、数値を受け取るオーバーロードは対応する数値型を変換します。整数変数を変換する前に、値が0~255の範囲内か確認してください。unchecked キャストでは、オーバーフローを報告せずに上位ビットが失われることがあります。

次の例を実行してください。

このセクションのコードと表示されるラベルや出力は英語のままです。

using System;

class Program
{
    static void Main()
    {
        string text = "42";
        byte fromText = Convert.ToByte(text);
        byte fromNumber = Convert.ToByte(90);
        Console.WriteLine($"{fromText}, {fromNumber}");
    }
}
42, 90

文字列を入力した場合、null文字列は0に変換されます。数値でないテキストでは FormatException が発生し、解析した値が0~255の範囲外なら OverflowException が発生します。

次の例では両方の失敗を処理し、捕捉した例外の型を表示するため、2つのケースを区別できます。FormatException は数値でないテキストが原因で、OverflowException は解析した値が255を超える場合に発生します。

次のエラー処理の例を実行してください。

using System;

class Program
{
    static void Main()
    {
        string[] inputs = { "twelve", "300" };

        foreach (string input in inputs)
        {
            try
            {
                byte value = Convert.ToByte(input);
                Console.WriteLine($"{input} -> {value}");
            }
            catch (FormatException)
            {
                Console.WriteLine($"{input} -> FormatException");
            }
            catch (OverflowException)
            {
                Console.WriteLine($"{input} -> OverflowException");
            }
        }
    }
}

文字列と基数を受け取るオーバーロード Convert.ToByte(value, fromBase) も、単一のbyteを返します。使用できる基数は2、8、10、16で、2~36までのすべての基数に対応するわけではありません。たとえば Convert.ToByte("FF", 16) は16進数の値を解析します。無効な数字を含む場合や、値がbyteの範囲に収まらない場合は変換エラーになります。対応していない基数を指定すると ArgumentException が発生します。このオーバーロードを、整数をバイト配列に変換するものとして説明しないでください。

BitConverter.GetBytes で int を byte[] に変換する

BitConverter.GetBytes(int) は、整数のバイナリ表現を格納した4バイトを返します。バイト順は現在のマシンに従い、BitConverter.IsLittleEndian で確認できます。次の完全な例では、バイトを十進数で表示し、マシンがネイティブに使うバイト順も示します。表示されるバイト順のラベルは、コードと出力のバイト単位の一致を保つため英語のままです。

using System;

class Program
{
    static void Main()
    {
        int value = 123456789;
        byte[] bytes = BitConverter.GetBytes(value);
        Console.WriteLine(string.Join(" ", bytes));
        Console.WriteLine(BitConverter.IsLittleEndian ? "Little-endian" : "Big-endian");
    }
}

受信側のコードが同じバイト順の規約を使う場合、この方法は便利です。バイトを別のシステムに保存または送信する場合は、両方のマシンが同じ順序を使うと想定せず、形式をあらかじめ合意してください。

BinaryWriter と MemoryStream で int を byte[] に書き込む

コードがすでに複数の値をストリームへ順番に書き込んでいる場合は、BinaryWriter で int を書き込み、MemoryStream.ToArray() で蓄積されたバイトを取得できます。BinaryWriter はプリミティブ数値をリトルエンディアンで書き込みます。バッファーへの書き込みが完了してからストリームの内容を読み取れるよう、内容を取得する前にwriterを破棄してください。writerを破棄するとストリームも破棄されますが、その後も ToArray() は使用できます。

このセクションのコードと表示されるラベルや出力は英語のままです。

using System;
using System.IO;

class Program
{
    static void Main()
    {
        int value = 987654321;
        byte[] bytes;

        using (MemoryStream stream = new MemoryStream())
        {
            using (BinaryWriter writer = new BinaryWriter(stream))
            {
                writer.Write(value);
            }

            bytes = stream.ToArray();
        }

        Console.WriteLine(string.Join(" ", bytes));
    }
}

この方法は、複数のフィールドを順番にシリアル化する場合に便利です。生成される配列には、最後に書き込んだ整数だけでなく、ストリーム全体の内容が含まれます。プロトコルで別のバイト順が指定されている場合は、そのプロトコルが要求する順序を使ってください。

int を byte[] に変換するときにバイト順を制御する

エンディアンは、最下位バイトと最上位バイトのどちらを先に並べるかを決めます。BitConverter.GetBytes はマシンのネイティブなバイト順に従うため、必要な形式とネイティブな順序が異なる場合にだけ、コピーを反転してください。次の例では、マシンのネイティブな順序にかかわらず、同じ値からリトルエンディアンとビッグエンディアンの両方の表現を作成します。コードが表示するバイト順のラベルは英語のままです。

using System;

class Program
{
    static void Main()
    {
        int value = 567890123;
        byte[] native = BitConverter.GetBytes(value);
        byte[] littleEndian = (byte[])native.Clone();
        byte[] bigEndian = (byte[])native.Clone();

        if (!BitConverter.IsLittleEndian)
        {
            Array.Reverse(littleEndian);
        }

        if (BitConverter.IsLittleEndian)
        {
            Array.Reverse(bigEndian);
        }

        Console.WriteLine("Little-endian: " + string.Join(" ", littleEndian));
        Console.WriteLine("Big-endian: " + string.Join(" ", bigEndian));
    }
}

バイトを書き込む境界または読み取る境界で、必要な順序を指定してください。固定幅整数の表現ではローカルの配列を反転してもかまいませんが、それだけでは完全なシリアル化形式になりません。形式では幅、符号の有無、複数フィールドの並び順も定める必要があります。