pack

バイナリーデータに変換する

構文

解説

pack は、TEMPLATE に与えられたルールに基づいて、LIST のそれぞれの値をバイナリーデータに変換し、変換したすべての値を結合したバイナリーデータを返します。 何かしらのバイナリーデータを扱う場合には、このバイナリーデータを生成する pack と、 バイナリーデータから意味を読み取る unpack は欠かすことができない関数です。 とりわけ、バイナリーファイルを扱う場合や、 ネットワーク上のパケット生成や解析においては避けては通れない関数です。

次のサンプルは IP アドレス "192.168.11.3" を 4 バイトのバイナリーデータに変換します。 バイナリーデータのままでは中身を確かめられないため、unpack を使って 16 進数表記の文字列として出力します。

my $bin = pack( 'C4', split(/\./, '192.168.11.3') ); 
print unpack('H*', $bin); # c0a80b03

このサンプルコードの pack に与えられた TEMPLATEC4 ですが、 C は符号なし 8 ビット整数 (unsigned char) を意味しており、 その後の 4 は 4 つという意味です。 つまり「1 バイトの 0 ~ 255 の値が 4 つ」という意味になります。 C4CCCC と記述することもできます。

split(/\./, '192.168.11.3')pack の引数の LIST に相当し、"192", "168", "11", "3" という 4 つの数字を表す文字列になります。

最終的には、"192" や "168" などの数字を表す文字列をそれぞれ 1 バイトの数値とみなしてバイナリーデータに変換し、それら 4 つを結合する、ということになります。

TEMPLATE には数多くの文字が定義されていますが、ここでは良く使われるテンプレート文字に限定して紹介します。 すべての仕様を確認したい場合は、 公式の Perldoc の説明をご覧ください。

文字 説明
a null 埋めの文字列
my $bin = pack( 'a5', 'Perl' ); 
print unpack('H*', $bin); # 5065726c00

TEMPLATEa5 で 5 文字を表しています。 しかし、LIST は 4 文字の文字列が 1 つです。 1 文字余るため、その部分は null (0x00) で埋め合わせられます。

utf8 フラグが ON の内部文字列を扱う場合は、Encode::encode() で外部文字列に変換してからパックするようにしてください。

use utf8;
use Encode;
my $bin = pack( 'a5', Encode::encode( 'UTF-8', 'あ' ) );
print unpack( 'H*', $bin );    # e381820000

外部文字列にした時点でバイナリーデータになります。 TEMPLATEa5 で 5 文字と指定されていますが、 実際に Perl は文字を認識していませんので、事実上、5 バイトと考えて問題ありません。 "あ" は UTF-8 エンコーディングではこの 1 文字で 3 バイトを消費します。 そのため、残りの 2 バイト分が null (0x00) で埋め合わされます。

A スペース埋めの文字列
my $bin = pack( 'A5', 'Perl' ); 
print unpack( 'H*', $bin );    # 5065726c20

テンプレート A は、半角スペース (0x20) で余りを埋めます。 それ以外の挙動はテンプレート a と全く同じです。

Z null 終端かつ null 埋めの文字列
pack( 'Z5', 'abcd' );      # 0x6162636400 (null で埋めて 5 バイトにする)
pack( 'Z5', 'abcde' );     # 0x6162636400 ("e" を null に置き換えて 5 バイトにする)
pack( 'Z5', 'abcdef' );    # 0x6162636400 ("e" を null に置き換え、以降を削除して 5 バイトにする)

テンプレート Z は、文字数を満たすよう余りに null (0x00) を埋めますが、 余りがないときは最後の 1 文字を null (0x00) にして、どんな状況でも必ず最後が null (0x00) となるようにします。 そのため、上記のサンプルコードの結果はすべて同じになります。

b ビット列 (各バイト内では昇ビット順で vec() と同様)
pack( 'b8', '00000001' ); # 0x80
pack( 'b8', '10000000' ); # 0x01

テンプレート b は、2 進数を表現した文字列をバイトに変換します。しかし、ビット順が逆になりますので注意してください。 "00000001" は 0x80 つまり 0b10000000 になり、"10000000" は 0x01 つまり 0b00000001 になります。

B ビット列 (各バイト内では降ビット順)
pack( 'B8', '00000001' ); # 0x01
pack( 'B8', '10000000' ); # 0x80

テンプレート B は、2 進数を表現した文字列をバイトに変換します。 "00000001" は 0x01 つまり 0b00000001 になり、"10000000" は 0x80 つまり 0b10000000 になります。

h 16 進数文字列 (低位ニブルが先)
pack( 'h4', '0a0b' );    # 0xa0b0

テンプレート h は、16 進数文字列をバイナリーに変換します。 ただし、ニブルが逆転しますので注意してください。 つまり、"0a" は 0xa0 に、"0b" は 0xb0 になります。

H 16 進数文字列 (高位ニブルが先)
pack( 'H4', '0a0b' );    # 0x0a0b

テンプレート H は、16 進数文字列をバイナリーに変換します。

c 符号付き 8 ビット整数 (signed char)
pack( 'c5', 2, 1, 0, -1, -2 );    # 0x020100fffe

テンプレート c は与えられた数値を符号付き 8 ビット整数 (signed char) のバイナリーに変換します。 1 は 0x01 に、-1 は 0xff になります。

C 符号なし 8 ビット整数 (unsigned char)
pack( 'C5', 0, 1, 2, 254, 255 );    # 0x000102feff

テンプレート C は与えられた数値を符号なし 8 ビット整数 (unsigned char) のバイナリーに変換します。 1 は 0x01 に、255 は 0xff に変換されます。

s 符号付き 16 ビット整数 (signed short)
pack( 's2', 1, -1);    # 0x0100ffff

テンプレート s は与えられた数値を符号付き 16 ビット整数 (signed short) のバイナリーに変換します。 バイトオーダーはリトルエンディアンです。 1 は 0x0100 に、-1 は 0xffff に変換されます。

S 符号なし 16 ビット整数 (unsigned short)
pack( 'S2', 1, 65535 );    # 0x0100ffff

テンプレート S は与えられた数値を符号なし 16 ビット整数 (unsigned short) のバイナリーに変換します。 バイトオーダーはリトルエンディアンです。 1 は 0x0100 に、65535 は 0xffff に変換されます。

l 符号付き 32 ビット整数 (signed long)
pack( 'l2', 1, -1 );    # 0x01000000ffffffff

テンプレート l は与えられた数値を符号付き 32 ビット整数 (signed long) のバイナリーに変換します。 バイトオーダーはリトルエンディアンです。 1 は 0x01000000 に、-1 は 0xffffffff に変換されます。

L 符号なし 32 ビット整数 (unsigned long)
pack( 'L2', 1, 4294967295 );    # 0x01000000ffffffff

テンプレート L は与えられた数値を符号なし 32 ビット整数 (unsigned long) のバイナリーに変換します。 バイトオーダーはリトルエンディアンです。 1 は 0x01000000 に、4294967295 は 0xffffffff に変換されます。

q 符号付き 64 ビット整数 (signed quad)
pack( 'q2', 1, -1 );    # 0x0100000000000000ffffffffffffffff

テンプレート q は与えられた数値を符号付き 64 ビット整数 (signed quad) のバイナリーに変換します。 バイトオーダーはリトルエンディアンです。 1 は 0x0100000000000000 に、-1 は 0xffffffffffffffff に変換されます。

なお、テンプレート q は、OS が 64 ビット整数をサポートし、かつ、Perl 自体が 64 ビット整数を扱えるようコンパイルされている必要があります。 そうでなければ例外が投げられます。

Q 符号なし 64 ビット整数 (unsigned quad)
pack( 'Q2', 1, 18446744073709551616 );    # 0x0100000000000000ffffffffffffffff

テンプレート Q は与えられた数値を符号なし 32 ビット整数 (unsigned long) のバイナリーに変換します。 バイトオーダーはリトルエンディアンです。 1 は 0x0100000000000000 に、18446744073709551616 は 0xffffffffffffffff に変換されます。

なお、テンプレート Q は、OS が 64 ビット整数をサポートし、かつ、Perl 自体が 64 ビット整数を扱えるようコンパイルされている必要があります。 そうでなければ例外が投げられます。

n 符号なし 16 ビット整数 (unsigned short) でビッグエンディアン
pack( 'n', 1 );      # 0x0001

テンプレート n は与えられた数値を符号なし 16 ビット整数 (unsigned short) でビッグエンディアンのバイナリーに変換します。 1 は 0x0001 に変換されます。

N 符号なし 32 ビット整数 (unsigned long) でビッグエンディアン
pack( 'N', 1 );      # 0x00000001

テンプレート N は与えられた数値を符号なし 32 ビット整数 (unsigned long) でビッグエンディアンのバイナリーに変換します。 1 は 0x00000001 に変換されます。

v 符号なし 16 ビット整数 (unsigned short) でリトルエンディアン
pack( 'v', 1 );      # 0x0100

テンプレート n は与えられた数値を符号なし 16 ビット整数 (unsigned short) でリトルエンディアンのバイナリーに変換します。 1 は 0x0100 に変換されます。 これは結果的にテンプレート文字 S と同じです。

V 符号なし 32 ビット整数 (unsigned long) でリトルエンディアン
pack( 'V', 1 );    # 0x01000000

テンプレート N は与えられた数値を符号なし 32 ビット整数 (unsigned long) でリトルエンディアンのバイナリーに変換します。 1 は 0x01000000 に変換されます。 これは結果的にテンプレート文字 L と同じです。

f 単精度浮動小数点数
pack( 'f', 0.1 );    # 0xcdcccc3d

テンプレート f は与えられた数値を単精度浮動小数点数のバイナリーに変換します。

d 倍精度浮動小数点数
pack( 'd', 0.1 );    # 0x9a9999999999b93f

テンプレート f は与えられた数値を倍精度浮動小数点数のバイナリーに変換します。

以上、良く使うテンプレート文字を解説しましたが、pack には他にも細かい機能が用意されています。 ウェブアプリケーション開発であればそこまで細かい機能を使うこともないでしょうが、もし興味があれば、 Perl 公式サイトのドキュメントをご覧ください。