你能解释一下我从解包中得到的信息吗?

发布于 2024-11-02 22:07:38 字数 657 浏览 3 评论 0原文

我对 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";

I'm relatively inexperienced with Perl, but my question concerns the unpack function when getting the bits for a numeric value. For example:

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

This results in 10001100 being printed, which is 140 in decimal. In the reverse order it's 49 in decimal. Any other values I've tried seem to give the incorrect bits.

However, when I run $bits through pack, it produces 1 again. Is there something I'm missing here?

It seems that I jumped to conclusions when I thought my problem was solved. Maybe I should briefly explain what it is I'm trying do.

I need to convert an integer value that could be as big as 24 bits long (the point being that it could be bigger than one byte) into a bit string. This much can be accomplished using unpack and pack as suggested by @ikegami, but I also need to find a way to convert that bit string back into it's original integer (not a string representation of it).

As I mentioned, I'm relatively inexperienced with Perl, and I've been trying with no success.


I found what seems to be an optimal solution:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

演出会有结束 2024-11-09 22:07:38

这可能是显而易见的,但其他答案没有明确指出: unpack("b*", 1) 中的第二个参数被类型转换为字符串 "1"< /code>,其十六进制 ASCII 值为 31(最高有效半字节在前)。

相应的二进制文件为 00110001,它在输出中反转为 10001100,因为您使用了 "b*" 而不是 "B *”。它们对应于二进制表示的相反“字节序”形式。 “字节顺序”就是最高有效位是位于二进制表示的开头还是结尾。

This might be obvious, but the other answers haven't pointed it out explicitly: The second argument in unpack("b*", 1) is being typecast to the string "1", which has an ASCII value of 31 in hex (with the most significant nibble first).

The corresponding binary would be 00110001, which is reversed to 10001100 in your output because you used "b*" instead of "B*". These correspond to the opposite "endian" forms of the binary representation. "Endian-ness" is just whether the most-significant bits go at the start or the end of the binary representation.

悲凉≈ 2024-11-09 22:07:38

您没有具体说明您的期望。我猜您正在期待00000001

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

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

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

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

You didn't specify what you expect. I'm guessing you're expecting 00000001.

That's the correct bits for the byte you provided, at least on non-EBCDIC systems. Remember, the input of unpack is a string (mostly strings of bytes). Perhaps you wanted

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

Update: As others have pointed out, the above gives 10000000. For 00000001, you'd use

unpack('B*', pack('C', 1))  # 00000001
海螺姑娘 2024-11-09 22:07:38

是的,您错过了不同的机器支持不同的“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))

Yes, you're missing that different machines support different "endianness". And Perl is treating 1 like '1' so ( 0x31 ). So, you're seeing 1 -> 1000 (in ascending order) and 3 -> 1100.

"Wrong" depends on perspective and whether or not you gave Perl enough information to know what encoding and endianness you wanted.

From pack:

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

I think this is what you want:

unpack( 'B*', chr(1))
海风掠过北极光 2024-11-09 22:07:38

您正在尝试将整数转换为二进制,然后再转换回来。虽然您可以使用 pack 然后 解压,更好的方法是使用 sprintfprintf 以及 % b 格式:

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

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

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

You're trying to convert an integer to binary and then back. While you can do that with pack and then unpack, the better way is to use sprintf or printf with the %b format:

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

To go the other way (converting a string of 0s & 1s to an integer), the best way is to use the oct function with a 0b prefix:

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

As the others explained, unpack expects a string to unpack, so if you have an integer, you first have to pack it into a string. The %b format expects an integer to begin with.

If you need to do a lot of this on bytes, and speed is crucial, you could build a lookup table:

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

print $binary[$int];  # Assuming $int is between 0 and 255
帅的被狗咬 2024-11-09 22:07:38

ord(1) 是 49。您一定想要 sprintf("%064b", 1) 之类的东西,尽管这看起来确实有点矫枉过正。

The ord(1) is 49. You must want something like sprintf("%064b", 1), although that does seem like overkill.

羅雙樹 2024-11-09 22:07:38

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

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

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

You want "B" instead of "b".

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

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

pack

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文