问题 你何时会使用unpack('h *'...)或pack('h *'...)?


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

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 代替 H 同 pack 要么 unpack  我正在寻找一个具体的例子;如果你知道一台机器组织它的字节,它是什么,你可以链接到它的一些文件?

我可以想到你可以做的例子 使用  h例如,当你不关心格式时,序列化一些数据,只要你能读回来,但是 H 对那个有用。我正在寻找一个例子 h 是 更多 有用的 H


9509
now


起源



答案:


回想一下糟糕的'天' MS-DOS 通过在寄存器上设置高半字节和低半字节并执行Interupt xx来控制某些OS功能。例如,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系统调用恢复信息...

perlport 对于Perl 5.8-8,您有针对目标的endianess的这些建议测试:

不同的CPU存储不同的整数和浮点数       订单(称为 字节序)和宽度(32位和64位是       今天最常见的)。这会影响您尝试传输的程序       二进制格式的数字,从一个CPU架构到另一个,       通常通过网络连接“直播”,或通过存储       数字到二级存储,如磁盘文件或磁带。

存储订单冲突使得数字完全混乱。如果一个       little-endian主机(Intel,VAX)商店 0x12345678 (305419896 在       十进制),一个大端主机(摩托罗拉,Sparc,PA)将其读作        0x78563412 (2018915346 十进制)。 Alpha和MIPS可以是:       Digital / Compaq以little-endian模式使用/使用它们; SGI / Cray使用       他们处于大端模式。在网络(套接字)中避免此问题       连接使用 pack 和 unpack格式 n 和 N,       “网络”订单。这些都保证是便携式的。

从perl 5.8.5开始,你也可以使用 > 和 < 修饰符       强制大端或小端字节顺序。如果你愿意,这很有用       例如,存储有符号整数或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

如果您需要区分可以使用的endian体系结构       其中一个变量设置如下:

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

不同的宽度甚至可以在相等的平台之间导致截断       字节顺序。较短宽度的平台失去了上部       数。除了避免之外,没有好的解决方案       传输或存储原始二进制数。

人们可以用两种方式绕过这两个问题。或       始终以文本格式传输和存储号码,而不是原始号码       二进制,或者考虑使用像 Data::Dumper (包括在       Perl 5.005的标准发行版和 Storable (包括在内       of perl 5.8)。将所有数据保存为文本可以显着简化问题。

v字符串最多只能移动 v2147483647 (0x7FFFFFFF), 那是       EBCDIC到底有多远,或者更准确地说是UTF-EBCDIC。

看起来 unpack("h*",...) 使用频率高于 pack("h*",...)。我注意到了 return qq'unpack("F", pack("h*", "$hex"))'; 用于 Deparse.pm 和 IO-Compress 使用 pack("*h",...) 在Perl 5.12中

如果你想进一步的例子,这里是一个 Google代码搜索列表。你可以看到 pack|unpack("h*"...) 是非常罕见的,主要与确定平台的结束有关...



答案: