こんにちは。
本日はエンディアン変換についてメモです。
概要
エンディアンは、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