13

在 Perl 中,packunpack两个用于将字节转换为十六进制的模板:

h    十六进制字符串(低 nybble 优先)。
H    一个十六进制字符串(高 nybble 优先)。

最好用一个例子来说明这一点:

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什么?拉里一定认为有人可能会使用它,否则他不会费心把它包括在内。

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

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

4

3 回答 3

12

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

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

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

- 编辑

这里是具体的源代码:在这里下载 Perl 5.00402 for DOS 解压,

在文件 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 中,您有以下建议的目标字节序测试:

不同的 CPU 以不同的顺序(称为字节序)和宽度(32 位和 64 位是当今最常见的)存储整数和浮点数。当您的程序试图以二进制格式将数字从一种 CPU 架构传输到另一种时,这会影响您的程序,通常是通过网络连接“实时”传输,或者将数字存储到磁盘文件或磁带等辅助存储设备中。

冲突的存储订单使数字变得一团糟。如果小端主机(英特尔、VAX)存储0x12345678305419896十进制),大端主机(摩托罗拉、Sparc、PA)将其读取为 0x785634122018915346十进制)。Alpha 和 MIPS 可以是: Digital/Compaq used/在 little-endian 模式下使用它们;SGI/Cray 在大端模式下使用它们。为了避免网络(套接字)连接中的这个问题,请使用packunpack格式nN,“网络”命令。这些保证是便携的。

从 perl 5.8.5 开始,您还可以使用>and<修饰符来强制使用 big-endian 或 little-endian 字节顺序。例如,如果您要存储有符号整数或 64 位整数,这将非常有用。

您可以通过解压缩以本机格式打包的数据结构来探索平台的字节顺序,例如:

   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

如果您需要区分字节序架构,您可以使用以下任一变量集:

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

即使在相同字节序的平台之间,不同的宽度也会导致截断。宽度较短的平台会丢失数字的上部。除了避免传输或存储原始二进制数外,这个问题没有好的解决方案。

人们可以通过两种方式解决这两个问题。总是以文本格式传输和存储数字,而不是原始二进制文件,或者考虑使用像Data::Dumper(包含在 Perl 5.005 的标准发行版中)和Storable(包含在 perl 5.8 中)的模块。将所有数据保存为文本可以显着简化问题。

v-strings 只能移植到v2147483647( 0x7FFFFFFF),这就是 EBCDIC,或者更准确地说是 UTF-EBCDIC 将走多远。

似乎unpack("h*",...)比使用更频繁pack("h*",...)。我确实注意到在 Perl 5.12 return qq'unpack("F", pack("h*", "$hex"))';中使用Deparse.pmIO-Compress使用pack("*h",...)

如果您想了解更多示例,请参阅Google 代码搜索列表。您可以看到pack|unpack("h*"...)相当罕见,主要与确定平台字节序有关......

于 2010-10-04T18:07:53.660 回答
4

我想这在向具有不同字节顺序的机器传输数据或从机器读取数据时很有用。如果某个进程希望以通常在内存中表示的方式接收数据,那么您最好以这种方式发送数据。

于 2010-10-04T17:16:57.283 回答
2

两者之间的区别仅与您使用的是大端还是小端数据有关。有时您无法控制数据的来源或目的地,因此要打包的Hh标志可以为您提供选择。V并且N出于同样的原因。

于 2010-10-04T17:17:19.070 回答