Perl unpack 函数
最后修改于 2025 年 4 月 4 日
Perl 的 unpack 函数将二进制数据转换为 Perl 值。它是 pack 的逆操作,对于二进制数据处理至关重要。
unpack 使用模板字符串来指定如何解释二进制数据。它可以从二进制结构中提取数字、字符串和其他数据类型。
基本定义
- 模板:指定数据格式的字符串(例如,“N”表示 32 位无符号整数)
- 二进制数据:需要解释的原始字节
- 字节序:端序(大端 vs 小端)
- 对齐:数据结构填充要求
- 字段:二进制结构中的单个数据元素
unpack 的基本用法
unpack 最简单的用法是从二进制数据中提取单个值。
#!/usr/bin/perl
use strict;
use warnings;
use v5.34.0;
my $binary = pack("N", 0xDEADBEEF);
my ($number) = unpack("N", $binary);
printf "Binary: %v02X\n", $binary;
printf "Unpacked: 0x%08X\n", $number;
我们打包一个 32 位无符号整数,然后将其解包。 “N”模板指定了网络(大端)字节序。结果与我们的原始值匹配。
$ ./basic.pl Binary: DE.AD.BE.EF Unpacked: 0xDEADBEEF
提取多个值
unpack 可以使用单个模板提取多个值。
#!/usr/bin/perl
use strict;
use warnings;
use v5.34.0;
my $data = pack("NnA4", 0xCAFEBABE, 42, "Perl");
my ($num1, $num2, $str) = unpack("NnA4", $data);
printf "Numbers: 0x%08X, %d\n", $num1, $num2;
print "String: $str\n";
此示例打包和解包三个值:一个 32 位整数、一个 16 位整数和一个 4 字节字符串。模板“NnA4”匹配打包的数据结构。
$ ./multiple.pl Numbers: 0xCAFEBABE, 42 String: Perl
字节序转换
unpack 可以在不同的字节序之间进行转换。
#!/usr/bin/perl
use strict;
use warnings;
use v5.34.0;
my $little_endian = pack("V", 0x12345678);
my ($big_endian) = unpack("N", $little_endian);
printf "Little-endian: %v02X\n", $little_endian;
printf "Converted to big-endian: 0x%08X\n", $big_endian;
我们将一个值以小端格式(“V”)打包,并以大端格式(“N”)解包。这演示了不同架构之间的字节序转换。
$ ./endian.pl Little-endian: 78.56.34.12 Converted to big-endian: 0x78563412
字符串提取
unpack 可以提取具有特定长度和编码的字符串。
#!/usr/bin/perl
use strict;
use warnings;
use v5.34.0;
my $binary = pack("A10A5", "Hello", "World");
my ($str1, $str2) = unpack("A10A5", $binary);
print "First string: '$str1'\n";
print "Second string: '$str2'\n";
此示例打包和解包两个空格填充的字符串。“A”模板提取 ASCII 字符串,默认情况下会修剪尾部空格。
$ ./strings.pl First string: 'Hello' Second string: 'World'
位操作
unpack 可以从二进制数据中提取单个位和位字段。
#!/usr/bin/perl
use strict;
use warnings;
use v5.34.0;
my $flags = pack("C", 0b10101100);
my ($bitfield) = unpack("b8", $flags);
print "Binary representation: $bitfield\n";
print "Bits 7-6: ", substr($bitfield, 0, 2), "\n";
print "Bit 3: ", substr($bitfield, 5, 1), "\n";
我们打包一个具有特定位模式的字节,并将其解包为二进制字符串。“b”模板使我们能够访问单个位进行检查。
$ ./bits.pl Binary representation: 00110101 Bits 7-6: 00 Bit 3: 1
十六进制转储解析
unpack 可以解析二进制数据的十六进制字符串表示。
#!/usr/bin/perl
use strict;
use warnings;
use v5.34.0;
my $hex_string = "DEADBEEFCAFE";
my $binary = pack("H*", $hex_string);
my @bytes = unpack("C*", $binary);
print "Hex string: $hex_string\n";
print "Bytes: ", join(", ", map { sprintf "0x%02X", $_ } @bytes), "\n";
这会将十六进制字符串转换为二进制,然后将其解包为单个字节。“H”模板处理十六进制数据,而“C”提取无符号字节。
$ ./hexdump.pl Hex string: DEADBEEFCAFE Bytes: 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE
复杂结构解析
unpack 可以处理具有混合数据类型的复杂二进制结构。
#!/usr/bin/perl
use strict;
use warnings;
use v5.34.0;
# Simulate a network packet header
my $packet = pack("nnNNa8",
0x8000, # version and flags
42, # packet ID
time(), # timestamp
128, # data length
"payload" # data type
);
my ($version_flags, $id, $timestamp, $length, $type) =
unpack("nnNNa8", $packet);
printf "Version: %d\n", ($version_flags >> 12) & 0xF;
printf "Packet ID: %d\n", $id;
printf "Timestamp: %s\n", scalar localtime $timestamp;
printf "Data length: %d\n", $length;
printf "Data type: '%s'\n", $type;
此示例演示了解析类似于网络数据包头的复杂二进制结构。我们使用不同的数据类型和大小提取和解释多个字段。
$ ./complex.pl Version: 8 Packet ID: 42 Timestamp: Wed Apr 5 14:30:22 2025 Data length: 128 Data type: 'payload'
最佳实践
- 验证输入:在解包前检查二进制数据长度
- 使用描述性模板:使格式可读且易于维护
- 处理字节序:明确指定字节序要求
- 检查返回值:验证解包后的数据是否符合预期
- 文档格式:详细注释复杂的二进制结构
来源
本教程介绍了 Perl 的 unpack 函数,并通过实际示例演示了各种场景下的二进制数据处理。
作者
列出 所有 Perl 教程。