32bit 整数を IPv4 アドレスに変換

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

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) & 0xFF
  • b = (n >> 16) & 0xFF
  • c = (n >> 8) & 0xFF
  • d = n & 0xFF

>> で右にずらして欲しい位置の 8bit を最下位に持ってきて、& 0xFF で下位 8bit だけ取り出します。0xFF255 (11111111 の 8 ビット) を表す 16 進数表記です。

ビット演算が苦手なら、n / 16777216 % 256 のように 割り算と剰余 で書いても同じ結果になります。シフトと割り算は等価です。

計算例

3232235777 (192.168.1.1 を整数化したもの) で試します。

  • 3232235777 >> 24 & 0xFF = 192
  • 3232235777 >> 16 & 0xFF = 168
  • 3232235777 >> 8 & 0xFF = 1
  • 3232235777 & 0xFF = 1

これを . で結合して "192.168.1.1" を得ます。最後に文字列化する join が要点です。

diagram (will load when visible)

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 のように最上位ビットが立つ値だと負の数になります。これを避けるため、ここでは 割り算と剰余 で書きました。167772162^24655362^162562^8 です。

JavaScript で 0xFFFFFFFF >> 24& 0xFF なし)を試すと、-1 になります。>> は符号付き右シフトなので符号拡張が起き、& 0xFF を付けない場合は負の数になります。(0xFFFFFFFF >> 24) & 0xFF のように & 0xFF でマスクすれば 255 が得られますが、192 << 24 のように最上位ビットが立つ入力では n >> 24 自体が負になる点に注意が必要です。IPv4 整数では掛け算 / 割り算で書いたほうが安全です。

範囲外への配慮

本問題では n04294967295 (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) を実装してください。n0 以上 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 つができることを確認しましょう。

  1. 整数 → IPv4 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. 整数 → IPv4 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. 右シフトと 0xFF マスクで 4 つのオクテットを取り出す
  2. . で連結したドット区切り文字列を返す
  3. 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"

ヒント

main.py
main.py
学習モード

メモ

32bit 整数を IPv4 アドレスに変換

⌘S で保存