你能解释我从解包中得到的东西吗?

时间:2011-04-21 20:05:38

标签: perl bits pack unpack

我对Perl相对缺乏经验,但我的问题是在获取数值的位时解压缩函数。例如:

my $bits = unpack("b*", 1);
print $bits;

这导致打印10001100,十进制140。按相反的顺序,它是十进制的49。我试过的任何其他值似乎都给出了不正确的位。

然而,当我通过pack运行$ bits时,它再次产生1。这里有什么我想念的吗?

当我认为我的问题得到解决时,似乎我得出了结论。也许我应该简要解释一下我正在尝试做什么。

我需要将一个可能大到24位长的整数值(可能大于一个字节)转换为位串。这可以使用@ikegami建议的unpack和pack来完成,但是我还需要找到一种方法将该位字符串转换回它的原始整数(不是它的字符串表示)。

正如我所提到的,我对Perl相对缺乏经验,而且我一直在尝试没有成功。


我发现了什么似乎是最佳解决方案:

my $bits = sprintf("%032b", $num);
print "$bits\n";
my $orig = unpack("N", pack("B32", substr("0" x 32 . $bits, -32)));
print "$orig\n";

6 个答案:

答案 0 :(得分:6)

这可能是显而易见的,但其他答案没有明确指出:unpack("b*", 1)中的第二个参数是字符串"1"的类型转换,其ASCII值为{{1在十六进制中(首先是最重要的半字节)。

相应的二进制文件为31,由于您使用的是00110001而不是10001100,因此会在输出中反转为"b*"。这些对应于二进制表示的相反“endian”形式。 “Endian-ness”只是最重要的位是在二进制表示的开头还是结尾。

答案 1 :(得分:3)

是的,您错过了不同的计算机支持不同的"endianness"。并且Perl正在1处理'1'所以(0x31)。所以,你看到1 - > 1000(按升序排列)和3 - > 1100。

“错误”取决于视角以及您是否给Perl足够的信息来了解您想要的编码和字节顺序。

来自pack

b A bit string (ascending bit order inside each byte, like vec()).
B A bit string (descending bit order inside each byte).

我认为这就是你想要的:

unpack( 'B*', chr(1))

答案 2 :(得分:2)

ord(1)是49.你必须要sprintf("%064b", 1)这样的东西,虽然这看起来有点矫枉过正。

答案 3 :(得分:2)

您正在尝试将整数转换为二进制,然后返回。虽然您可以使用pack然后unpack执行此操作,但更好的方法是使用sprintfprintf %b格式:

my $int = 5;
my $bits = sprintf "%024b\n", $int;
print "$bits\n";

要采用另一种方式(将0和1的字符串转换为整数),最好的方法是使用带有0b前缀的oct函数:

my $orig = oct("0b$bits");
print "$orig\n";

正如其他人所解释的那样,unpack需要一个字符串来解包,所以如果你有一个整数,你首先必须将它pack变成一个字符串。 %b格式需要以整数开头。

如果你需要在字节上做很多事情,速度至关重要,你可以建立一个查找表:

my @binary = map { sprintf '%08b', $_ } 0 .. 255;

print $binary[$int];  # Assuming $int is between 0 and 255

答案 4 :(得分:1)

您没有指定您的期望。我猜你在期待00000001

这是您提供的字节的正确位,至少在非EBCDIC系统上是这样。请记住,unpack的输入是一个字符串(主要是字节串)。也许你想要

unpack('b*', pack('C', 1))

更新:正如其他人所指出的那样,上面给出了10000000。对于00000001,您可以使用

unpack('B*', pack('C', 1))  # 00000001

答案 5 :(得分:0)

你想要“B”而不是“b”。

$ perl -E'say unpack "b*", "1"'
10001100

$ perl -E'say unpack "B*", "1"'
00110001

pack