[C#] byte order

ちょっとハマったのでまとめる。

IPアドレスをソースコードで何らかの処理を行うために整数にしたい、とする。
直接、整数を作るメソッドがないので、まず、IPアドレスから配列を作る。

UnicastIPAddressInformation ipaddr;
Byte[] addrbytes = ipaddr.Address.GetAddressBytes();
Byte[] netmaskbytes = ipaddr.IPv4Mask.GetAddressBytes();

この結果得られる配列はnetwork orderであり、インデックス[0]にアドレス表記の最上位(A.B.C.DのA)が入る。
network orderの配列からIPアドレスを得るには

IPAddress(addrbytes)

のようにする。このコンストラクタIPAddress()に渡す配列はnetwork orderにすることが以下のように明記されている。
http://msdn.microsoft.com/en-us/library/t4k07yby.aspx
IPAddress Constructor

The Byte array is assumed to be in network byte order with the most significant byte first in index position 0.

IPアドレスを数値として処理するには、このGetAddressBytesの結果の配列からhost orderの整数にする必要がある。

配列から整数を構成するときによく使うstaticメソッドBitConverter.ToInt32()はbyte orderを保存する。
そのため、
myuint = (UInt32)BitConverter.ToInt32(addrbytes,0);
を実行すると、上位から、addrbytes[3],addrbytes[2],addrbytes[1],addrbytes[0]の順に並んだ整数ができる。このようにnetwork orderの配列から生成したUInt32はlittle endian のUInt32として使うと予期した値になっていない。

正しくは、host orderからnetwork orderへの変換を行うstatic methodを使って

myuint = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(addrbytes, 0));

で変換する。

little endian用だとわかっていれば

addr = (UInt32)(addrbytes[0] << 24 | addrbytes[1] << 16 |addrbytes[2] << 8 | addrbytes[3]);

というeidian依存のやり方で十分かもしれない。

これをIPアドレスに戻すには、IPアドレスをnetwork orderのbyte[]に入れてIPAddress()コンストラクタに引数として与える。

               UInt32 newhost; // 演算処理されたhost order のIPアドレス
newhost = (UInt32)IPAddress.HostToNetworkOrder((int)newhost);
IPAddress ip = new IPAddress((BitConverter.GetBytes((newhost))));

のようにした。

msdnのBitConverter classの説明には、C#のメソッドで配列を逆転させるコード例が掲載されている。
http://msdn.microsoft.com/en-us/library/System.BitConverter.aspx
BitConverter Class

   private static byte[] ReverseBytes(byte[] inArray)
   {
      byte temp;
      int highCtr = inArray.Length - 1;

      for (int ctr = 0; ctr < inArray.Length / 2; ctr++)
      {
         temp = inArray[ctr];
         inArray[ctr] = inArray[highCtr];
         inArray[highCtr] = temp;
         highCtr -= 1;
      }
      return inArray;
   }
広告

コメントを残す

コメントを投稿するには、以下のいずれかでログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。