32bit 整数を IPv4 アドレスに変換
ログに 3232235777 と出ていても、誰の接続なのかは分かりません。保存や比較のために整数へ直したものは、人に見せる前に元の表記へ戻す必要があります。前回の逆をたどります。
数のままでは、誰も読めない
整数は機械にとって扱いやすく、人にとっては読めません。DB には整数で入れておき、画面やログに出す直前に点で区切った形へ戻す、という使い分けをします。詰めるときに上から順に載せたので、戻すときも上から順に取り出します。
整数のまま持っておく利点も、ここで確かめておきます。1 つの数なら、範囲の判定も並べ替えも索引も素直に効きます。読めないという欠点は、出す直前に直せば済む話です。
上の桁から順に取り出す
日付を 1 つの整数に詰めたものから、年と月と日を取り出す例で考えます。
Python
packed = 20260826
year = packed // 10000
month = packed // 100 % 100
day = packed % 100
print(year, month, day) # 2026 8 26上の桁がほしいときは大きい数で割って下を落とします。真ん中がほしいときは、割って下を落としてから、余りで上を落とします。一番下は余りを取るだけです。上下から挟んで 1 つ取り出す、という手順は変わりません。
10 進で // と % を使ったところが、2 進では右へずらす >> と & 0xFF にあたります。IPv4 は 8 ビットずつ 4 つに分かれているので、ずらす量は 8 の倍数です。一番下のオクテットは、もう右端にいるのでずらす必要がありません。
取り出したあとの値は、必ず 0 から 255 のあいだに収まっているはずです。300 のような値が出てきたら、下 8 ビットだけを残す手順が抜けていて、上のビットが混ざっています。
プレーンテキスト
134744072 を 4 つに分ける
上から 8 | 8 | 8 | 8
つないで 8.8.8.8並べる向きを間違えると、逆さまになる
取り出した 4 つを点でつなぐとき、上のオクテットが先です。順番を取り違えると 1.1.168.192 のように反対から並んだ文字列ができます。値としては 4 つとも正しいので、目で見ても気づけません。テストで初めて分かります。
文字列にするところにも罠があります。数どうしを + でつなぐと、連結ではなく足し算になってしまうことがあります。書式指定を使うか、いったん文字列に直してから連結します。区切りの点は 3 つで、両端には付きません。
JavaScript では >> が符号付きの右シフトなので、最上位のビットが 1 の値を扱うと符号が広がって負の数が出てきます。
JavaScript
console.log(0xFFFFFFFF >> 4); // -1
console.log(0xFFFFFFFF >>> 4); // 268435455>> は空いた上の桁に符号を詰めるので、いくらずらしても負のままです。ここでも割り算と余りで書くほうが安全です。
標準ライブラリにも同じ変換があります。Python なら ipaddress の一族が、点で区切った表記と整数の行き来をまとめて面倒を見てくれます。実務ではそちらを使いますが、中で何が起きているかを一度手で書いておくと、値がおかしいときにどこを見ればよいかが分かります。
なお、詰める関数と戻す関数を続けて呼べば、必ず元の値に戻るはずです。この往復が一致するかどうかは、片方だけを見ていても分からない間違いを見つけてくれます。
要件
- 右シフトと 0xFF マスクで 4 つのオクテットを取り出す
- . で連結したドット区切り文字列を返す
- 0 のときは '0.0.0.0' を返す
入出力例
intToIp(0) → "0.0.0.0"
intToIp(2130706433) → "127.0.0.1"
intToIp(3232235777) → "192.168.1.1"
intToIp(4294967295) → "255.255.255.255"
intToIp(167772161) → "10.0.0.1"
intToIp(134744072) → "8.8.8.8"
intToIp(2886729729) → "172.16.0.1"