perl - 你什么时候使用 unpack ('h*' ...) 或 pack ('h*' ...)?

标签 perl hex pack unpack

在 Perl 中, pack unpack 有两个模板用于将字节转换为/从十六进制:

h    A hex string (low nybble first).
H    A hex string (high nybble first).



最好通过一个例子来说明这一点:
use 5.010; # so I can use say
my $buf = "\x12\x34\x56\x78";

say unpack('H*', $buf); # prints 12345678
say unpack('h*', $buf); # prints 21436587

如您所见,H 是人们在考虑将字节转换为十六进制/从十六进制转换时通常的意思。那么 h 的目的是什么? Larry 一定认为有人可能会使用它,否则他不会费心把它包括在内。

你能举一个真实的例子,你实际上想要使用 h 而不是 Hpackunpack 吗? 我正在寻找一个具体的例子;如果你知道一台机器像这样组织它的字节,它是什么,你能链接到一些关于它的文档吗?

我可以想到可以使用 h 的示例,例如当您并不真正关心格式是什么时序列化一些数据,只要您可以读回它,但是 H 对此同样有用。我正在寻找一个示例,其中 hH 更有用。

最佳答案

回想一下 MS-DOS 的糟糕日子,某些 OS 功能是通过在寄存器上设置高半字节和低半字节并执行 Interupt xx 来控制的。例如,Int 21 访问了许多文件函数。您可以将高半字节设置为驱动器编号——谁将拥有超过 15 个驱动器?作为该驱动器上请求功能的低半字节等。

Here 是一些旧的 CPAN 代码,它使用您描述的包来设置寄存器以执行 MS-DOS 系统调用。

布莱克!!!我一点也不怀念 MS-DOS...

- 编辑

下面是具体的源代码:下载 Perl 5.00402 for DOS HERE ,解压,

在文件 Opcode.pm 和 Opcode.pl 中,您可以在这里看到 unpack("h*",$_[0]); 的使用:

sub opset_to_hex ($) {
    return "(invalid opset)" unless verify_opset($_[0]);
    unpack("h*",$_[0]);
}

我没有完全遵循代码,但我怀疑这是从 MS-DOS 系统调用中恢复信息......

在 Perl 5.8-8 的 perlport 中,您有这些建议的目标字节序测试:

Different CPUs store integers and floating point numbers in different orders (called endianness) and widths (32-bit and 64-bit being the most common today). This affects your programs when they attempt to transfer numbers in binary format from one CPU architecture to another, usually either “live” via network connection, or by storing the numbers to secondary storage such as a disk file or tape.

Conflicting storage orders make utter mess out of the numbers. If a little-endian host (Intel, VAX) stores 0x12345678 (305419896 in decimal), a big-endian host (Motorola, Sparc, PA) reads it as 0x78563412 (2018915346 in decimal). Alpha and MIPS can be either: Digital/Compaq used/uses them in little-endian mode; SGI/Cray uses them in big-endian mode. To avoid this problem in network (socket) connections use the pack and unpack formats n and N, the “network” orders. These are guaranteed to be portable.

As of perl 5.8.5, you can also use the > and < modifiers to force big- or little-endian byte-order. This is useful if you want to store signed integers or 64-bit integers, for example.

You can explore the endianness of your platform by unpacking a data structure packed in native format such as:

   print unpack("h*", pack("s2", 1, 2)), "\n";
   # '10002000' on e.g. Intel x86 or Alpha 21064 in little-endian mode
   # '00100020' on e.g. Motorola 68040

If you need to distinguish between endian architectures you could use either of the variables set like so:

   $is_big_endian    = unpack("h*", pack("s", 1)) =~ /01/;
   $is_little_endian = unpack("h*", pack("s", 1)) =~ /^1/;

Differing widths can cause truncation even between platforms of equal endianness. The platform of shorter width loses the upper parts of the number. There is no good solution for this problem except to avoid transferring or storing raw binary numbers.

One can circumnavigate both these problems in two ways. Either transfer and store numbers always in text format, instead of raw binary, or else consider using modules like Data::Dumper (included in the standard distribution as of Perl 5.005) and Storable (included as of perl 5.8). Keeping all data as text significantly simplifies matters.

The v-strings are portable only up to v2147483647 (0x7FFFFFFF), that's how far EBCDIC, or more precisely UTF-EBCDIC will go.



似乎 unpack("h*",...)pack("h*",...) 更常用。我确实注意到 return qq'unpack("F", pack("h*", "$hex"))';Deparse.pm 中使用,IO-Compress 在 Perl 5.12 中使用 pack("*h",...)
如果你想要更多的例子,这里有一个 Google Code Search list 。您可以看到 pack|unpack("h*"...) 相当罕见,主要用于确定平台字节序...

关于perl - 你什么时候使用 unpack ('h*' ...) 或 pack ('h*' ...)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3857499/

相关文章:

perl - 如何重定向 Perl 的 Test::Simple 的测试输出?

sql - 如何使用 Perl 连接到 Sybase?

api - 网站如何加密 API 响应?

NPM 包,包括 .DS_Store

java - 在 borderlayout 中使用 JPanel 错误打包 JFrame

perl - Perl 中的 BigQuery : append query data to table

perl - 使用 Plack::Handler::Apache2 与 Apache2 的 PSGI 应用程序导致 'not found'

javascript - 将十六进制数转换为数组

c - C 如何将有符号的十六进制数转换为负数?

php5 包在 x84_64 env 上损坏