なんだかGoodVibes

日々の勉強メモです。

【C#】エンディアン変換について

こんにちは。
本日はエンディアン変換についてメモです。


概要

エンディアンは、2バイトの並びの方式のことです。
ビックエンディアン・リトルエンディアンが存在します。
下位のバイトから並べるのがリトルエンディアン
上位のバイトから並べるのがビックエンディアンです。

エンディアンはCPUによって決まっていて
データを通信でやりとりするような場面でエンディアン変換が
必要になってきます。
例えば、送信側がリトルエンディアンのCPUで
通信がビックエンディアンだった場合、
受信側はデータをエンディアン変換しなければいけません。


シフト演算でエンディアン変換する

int(4byte)をエンディアン変換するサンプルです。

static void Main()
{
    var num = 0x10203040;
    var b1 = (num >> 0) & 0xff;
    var b2 = (num >> 8) & 0xff;
    var b3 = (num >> 16) & 0xff;
    var b4 = (num >> 24) & 0xff;
    var result = b1 << 24 | b2 << 16 | b3 << 8 | b4;
    
    Console.WriteLine("\n[変換前]");
    PrintBinary(Convert.ToString(num, 2).PadLeft(32, '0'));
    PrintHexadecimal(Convert.ToString(num, 16).PadLeft(8, '0'));
    
    Console.WriteLine("[変換後]");
    PrintBinary(Convert.ToString(result, 2).PadLeft(32, '0'));
    PrintHexadecimal(Convert.ToString(result, 16).PadLeft(8, '0'));
}

private static void PrintBinary(string t)
{
    var result = string.Empty;
    for (int i = 0; i < t.Length; i++)
    {
        result = result + t[i];
        
        if ((i + 1) % 8 == 0)
        {
            result = result + " ";
        }
    }

    Console.WriteLine($"\t2進数 = {result}");
}

private static void PrintHexadecimal(string t)
{
    var result = string.Empty;
    for (int i = 0; i < t.Length; i++)
    {
        result = result + t[i];
        
        if ((i + 1) % 2 == 0)
        {
            result = result + " ";
        }
    }

    Console.WriteLine($"\t16進数 = {result}");
}

結果は以下のようになります。

[変換前]
        2進数 = 00010000 00100000 00110000 01000000
        16進数 = 10 20 30 40
[変換後]
        2進数 = 01000000 00110000 00100000 00010000
        16進数 = 40 30 20 10

シフトしている部分を調整することで
short(2byte)、long(8byte)用の関数を作成することもできます。


BitConverterを使ってエンディアン変換する

int(4byte)をエンディアン変換するサンプルです。

static void Main()
{
    var bytes  = BitConverter.GetBytes(0x10203040);
    var big    = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(0x10203040));
    var little = BitConverter.GetBytes(IPAddress.NetworkToHostOrder(BitConverter.ToInt32(big, 0)));

    var b = string.Join(' ', bytes.Select(x => $"{int.Parse(Convert.ToString(x, 2)):D8}"));
    var h = string.Join(' ', bytes.Select(x => $"{int.Parse(Convert.ToString(x, 16)):D2}"));
    
    var bb = string.Join(' ', big.Select(x => $"{int.Parse(Convert.ToString(x, 2)):D8}"));
    var hb = string.Join(' ', big.Select(x => $"{int.Parse(Convert.ToString(x, 16)):D2}"));
    
    var bl = string.Join(' ', little.Select(x => $"{int.Parse(Convert.ToString(x, 2)):D8}"));
    var hl = string.Join(' ', little.Select(x => $"{int.Parse(Convert.ToString(x, 16)):D2}"));
    
    Console.WriteLine("\n[変換前(byte)]");
    Console.WriteLine($"\t2進数 = {b}");
    Console.WriteLine($"\t16進数 = {h}");
    
    Console.WriteLine("[変換後(Big)]");
    Console.WriteLine($"\t2進数 = {bb}");
    Console.WriteLine($"\t16進数 = {hb}");
    
    Console.WriteLine("[変換後(Little)]");
    Console.WriteLine($"\t2進数 = {bl}");
    Console.WriteLine($"\t16進数 = {hl}");
}

private static void PrintBinary(string t)
{
    var result = string.Empty;
    for (int i = 0; i < t.Length; i++)
    {
        result = result + t[i];
        
        if ((i + 1) % 8 == 0)
        {
            result = result + " ";
        }
    }

    Console.WriteLine($"\t2進数 = {result}");
}

private static void PrintHexadecimal(string t)
{
    var result = string.Empty;
    for (int i = 0; i < t.Length; i++)
    {
        result = result + t[i];
        
        if ((i + 1) % 2 == 0)
        {
            result = result + " ";
        }
    }

    Console.WriteLine($"\t16進数 = {result}");
}

結果は以下です。

[変換前(byte)]
        2進数 = 01000000 00110000 00100000 00010000
        16進数 = 40 30 20 10
[変換後(Big)]
        2進数 = 00010000 00100000 00110000 01000000
        16進数 = 10 20 30 40
[変換後(Little)]
        2進数 = 01000000 00110000 00100000 00010000
        16進数 = 40 30 20 10


まとめ