IPv4 アドレスを 32bit 整数に変換
IPv4 アドレスを 32bit 整数に変換
このレッスンで分かること
192.168.1.1のような表記の IPv4 アドレスを、内部的には 1 つの 32bit 整数 として扱うとさまざまな処理が一瞬で書けるようになります- IPv4 アドレスは 4 つのオクテット (8bit × 4 = 32bit) で構成されています
- 4 つのオクテット
a.b.c.dを 32bit 整数にするには、それぞれを 8bit ずつ位置をずらして足し合わせます
IPv4 アドレスを 32bit 整数に変換 とは
192.168.1.1 のような IPv4 アドレスを 32bit の整数に変換する関数を作ります。本レッスンでは、IPv4 アドレスを 32bit 整数に変換 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
192.168.1.1 のような表記の IPv4 アドレスを、内部的には 1 つの 32bit 整数 として扱うとさまざまな処理が一瞬で書けるようになります。本レッスンでは、ドット区切り表記 (dotted quad) を整数に変換する関数を実装します。
なぜ整数に変換するのか
IPv4 アドレスは 4 つのオクテット (8bit × 4 = 32bit) で構成されています。文字列のまま比較しようとすると辞書順比較になり、9.0.0.0 と 10.0.0.0 の大小判定で誤った結果が出ます ("9" > "10" になる)。整数化すれば次のメリットがあります。
- 比較や大小判定が
O(1)で正しく行える - CIDR (
192.168.1.0/24) との一致判定がbit AND1 回でできる - データベースに 1 カラム (
UNSIGNED INT) で格納でき、インデックスも効く - ルーティングテーブルでの 最長一致 も整数演算で簡単
ネットワーク機器の内部では IPv4 を
uint32で扱うのが普通です。文字列表現は人間向けのインターフェースに過ぎません。
計算の考え方
4 つのオクテット a.b.c.d を 32bit 整数にするには、それぞれを 8bit ずつ位置をずらして足し合わせます。式は次の通りです。
result = (a << 24) | (b << 16) | (c << 8) | d
つまり a が最上位 8bit、d が最下位 8bit です。192.168.1.1 を計算してみます。
192 << 24=3221225472168 << 16=110100481 << 8=2561=1- 合計 =
3232235777
図のポイント (テキスト併記)
-
<<はビット左シフトで、x << 8はx * 256と同じです
<<はビット左シフトで、x << 8はx * 256と同じです。|は OR で、ここでは+でも結果は同じです (オクテット同士は重ならないため)。
Python 実装
Python
def ipToInt(ip):
parts = ip.split('.')
a, b, c, d = (int(p) for p in parts)
return (a << 24) | (b << 16) | (c << 8) | dsplit でドットを区切ってリスト化し、それぞれを整数に変換します。続いてビット演算で 32bit に詰めます。Python の整数は任意精度なので 3221225472 のような大きな値もそのまま扱えます。
JavaScript 実装
JavaScript
function ipToInt(ip) {
const parts = ip.split('.').map(Number);
return parts[0] * 16777216 + parts[1] * 65536 + parts[2] * 256 + parts[3];
}JavaScript のビット演算は 32bit 符号付き なので、192.168.1.1 のように最上位ビットが立つ値だと << を使うと負の数になります。これを避けるため * 16777216 のように 掛け算で書く のが定石です。16777216 は 2^24、65536 は 2^16、256 は 2^8 です。
JavaScript で
(192 << 24)を試すと-1073741824になります。符号付きビット演算の罠です。>>> 0で符号なしに戻すこともできますが、掛け算のほうが安全です。
入力の前提と検証
本問題では ip は 正しい形式の IPv4 であると仮定します (a.b.c.d、各オクテットは 0 〜 255 の整数)。実務では inet_aton / inet_pton のような標準ライブラリを使うのが安全です。Python なら import ipaddress; int(ipaddress.IPv4Address(ip)) が一番堅牢な書き方です。
具体例
"0.0.0.0"→0"127.0.0.1"→2130706433"192.168.1.1"→3232235777"255.255.255.255"→4294967295(32bit の最大値)"10.0.0.1"→167772161
255.255.255.255の整数表現4294967295は2^32 - 1で、これより大きい値は IPv4 では表現できません。
よくある間違い
- ドットで
splitした結果を文字列のまま掛け算してしまう ('192' * 256のようなバグ) - JavaScript で
<<を使い、最上位ビットが立つ値で負の数になる - 並び順を間違えて
(d << 24) | ...のように逆順に詰めてしまう - IPv6 (
::1) を渡されることを想定せず、split('.')で 4 個未満になっても気付かない - オクテットの上限
255を超えるバリデーションを怠る
やってみよう
関数 ipToInt(ip) を実装してください。引数 ip はドット区切りの IPv4 文字列 (例: "192.168.1.1") で、対応する 32bit 整数 (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 などを組み合わせて識別します。プライバシー保護の観点でも単一情報では追跡できません。
次のレッスン
次は 32bit 整数を IPv4 アドレスに変換 に進みましょう。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- IPv4 → 整数 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. IPv4 → 整数 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- ドット区切りの IPv4 文字列を 32bit 整数に変換する
- オクテットの順序は (a << 24) | (b << 16) | (c << 8) | d とする
- 255.255.255.255 が 4294967295 になるよう、符号なしの値として扱う
入出力例
test-cases.txt
ipToInt("0.0.0.0") → 0
ipToInt("127.0.0.1") → 2130706433
ipToInt("192.168.1.1") → 3232235777
ipToInt("255.255.255.255") → 4294967295
ipToInt("10.0.0.1") → 167772161
ipToInt("172.16.0.1") → 2886729729
ipToInt("8.8.8.8") → 134744072