32bit 整数を IPv4 アドレスに変換
32bit 整数を IPv4 アドレスに変換
このレッスンで分かること
- 32bit 整数は 4 つのオクテット (8bit) の連結です
>>で右にずらして欲しい位置の 8bit を最下位に持ってきて、& 0xFFで下位 8bit だけ取り出します3232235777(192.168.1.1を整数化したもの) で試します
32bit 整数を IPv4 アドレスに変換 とは
32bit の整数を 192.168.1.1 のような IPv4 文字列に戻す関数を実装します。前レッスンの逆操作です。
前のレッスンでは 192.168.1.1 のような文字列を 3232235777 という 32bit 整数に変換しました。今度はその 逆向きの操作 を実装します。整数のままだと人間が読めないので、ログ出力や UI 表示の前に文字列に戻すことになります。
整数から取り出す各オクテット
32bit 整数は 4 つのオクテット (8bit) の連結です。最上位の 8bit から順に取り出すには、ビットシフトと AND マスクを組み合わせます。
a = (n >> 24) & 0xFFb = (n >> 16) & 0xFFc = (n >> 8) & 0xFFd = n & 0xFF
>> で右にずらして欲しい位置の 8bit を最下位に持ってきて、& 0xFF で下位 8bit だけ取り出します。0xFF は 255 (11111111 の 8 ビット) を表す 16 進数表記です。
ビット演算が苦手なら、
n / 16777216 % 256のように 割り算と剰余 で書いても同じ結果になります。シフトと割り算は等価です。
計算例
3232235777 (192.168.1.1 を整数化したもの) で試します。
3232235777 >> 24 & 0xFF=1923232235777 >> 16 & 0xFF=1683232235777 >> 8 & 0xFF=13232235777 & 0xFF=1
これを . で結合して "192.168.1.1" を得ます。最後に文字列化する join が要点です。
Python 実装
Python
def intToIp(n):
a = (n >> 24) & 0xFF
b = (n >> 16) & 0xFF
c = (n >> 8) & 0xFF
d = n & 0xFF
return f"{a}.{b}.{c}.{d}"f-string で 4 つの整数をドット区切りに結合しています。Python の整数は任意精度なので、>> 24 を使っても問題ありません。
Python
def intToIp(n):
return ".".join(str((n >> (24 - 8 * i)) & 0xFF) for i in range(4))上の書き方を短くするとこのようになります。読みやすさを優先するなら最初の冗長な書き方のほうが向いていることが多いです。
JavaScript 実装
JavaScript
function intToIp(n) {
const a = Math.floor(n / 16777216) % 256;
const b = Math.floor(n / 65536) % 256;
const c = Math.floor(n / 256) % 256;
const d = n % 256;
return `${a}.${b}.${c}.${d}`;
}JavaScript のビット演算は 32bit 符号付き なので、192 << 24 のように最上位ビットが立つ値だと負の数になります。これを避けるため、ここでは 割り算と剰余 で書きました。16777216 は 2^24、65536 は 2^16、256 は 2^8 です。
JavaScript で
0xFFFFFFFF >> 24(& 0xFFなし)を試すと、-1になります。>>は符号付き右シフトなので符号拡張が起き、& 0xFFを付けない場合は負の数になります。(0xFFFFFFFF >> 24) & 0xFFのように& 0xFFでマスクすれば255が得られますが、192 << 24のように最上位ビットが立つ入力ではn >> 24自体が負になる点に注意が必要です。IPv4 整数では掛け算 / 割り算で書いたほうが安全です。
範囲外への配慮
本問題では n は 0 〜 4294967295 (2^32 - 1) の範囲を仮定します。範囲外の入力を渡された場合の挙動は未定義です。実務では inet_ntoa などの標準ライブラリを使うのが安全で、Python なら socket.inet_ntoa(struct.pack(">I", n)) の 1 行で書けます。
具体例
0→"0.0.0.0"2130706433→"127.0.0.1"3232235777→"192.168.1.1"4294967295→"255.255.255.255"167772161→"10.0.0.1"134744072→"8.8.8.8"
cs-ip-to-intで作った関数と組み合わせると、整数 → 文字列 → 整数 が ID 関数 (恒等) になることを確認できます。これは設計上の 可逆性 チェックです。
よくある間違い
- 並びを逆にしてしまう (
d.c.b.aのように低位から組み立てる) - マスク
& 0xFFを忘れ、上位ビットが残ったまま300のような値になる - JavaScript で
(n >> 24)を使い、負の数になってしまう f-stringではなく+で連結し、暗黙の数値演算が走ってしまう- 整数除算と通常除算の違いに気付かず、
192.0.168.0...のような結果になる
やってみよう
関数 intToIp(n) を実装してください。n は 0 以上 4294967295 以下の整数で、対応する IPv4 文字列を返します。0 のときは "0.0.0.0" を返します。
よくある質問
Q. IPv4 と IPv6 はどう違いますか?
A. IPv4 は 32 ビット(約 43 億個)、IPv6 は 128 ビット(事実上無限)のアドレス空間です。IPv4 アドレス枯渇問題への解として IPv6 が登場し、両者は併存しています(デュアルスタック)。サーバー設計では両方に対応するのが現代的です。
Q. プライベート IP とグローバル IP の違いは?
A. プライベート IP(192.168.x.x、10.x.x.x、172.16-31.x.x)は組織内だけで有効、グローバル IP はインターネット上で一意です。家庭の機器はプライベート IP を持ち、NAT でグローバル IP に変換されて外と通信します。
Q. IP アドレスからユーザーを特定できますか?
A. 完全な特定はできません。IP は接続元のおおよその地域とプロバイダを示すだけで、複数ユーザーで共有されることも多いです。ログ調査では IP + ユーザーエージェント + Cookie などを組み合わせて識別します。プライバシー保護の観点でも単一情報では追跡できません。
次のレッスン
次は CIDR プレフィックスからネットマスクを作る に進みましょう。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- 整数 → IPv4 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 整数 → IPv4 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- 右シフトと 0xFF マスクで 4 つのオクテットを取り出す
- . で連結したドット区切り文字列を返す
- 0 のときは '0.0.0.0' を返す
入出力例
test-cases.txt
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"