Decoding 3-byte integer in Perl

百般思念 提交于 2020-01-07 05:34:09

问题


I'm reading a binary file format that starts out with 4 constant check bytes, followed by 3 octets that indicate how long the data portion of the record will be. I can decode this as follows:

read($fh, $x, 7) or do {
  last if eof;
  die "Can't read: $!";
};
my ($type, $l1, $l2, $l3) = unpack("a4 C3", $x);
my $length = $l1 << 16 | $l2 << 8 | $l3;

Is there a more direct way to read that 3-byte value, without intermediate variables? Something I'm missing in the pack specifications maybe? I haven't used pack very much except for hex encoding and other dilettantish pursuits.


回答1:


No, unpack doesn't support 3-byte (or arbitrary length) integers, but you could use an unsigned 16-bit big-endian int to save a little work:

my ($type, $l1, $l23) = unpack("a4 Cn", $x);
my $length = $l1 << 16 | $l23;



回答2:


You could insert a null byte into the string in order to be able to use the "N" format:

substr($x, 4, 0, "\0");
my ($type, $length) = unpack "a4 N", $x;

Edit: Or else unpack in two steps:

my ($type, $length) = unpack "a4 a3", $x;
$length = unpack "N", "\0" . $length;



回答3:


my $type = unpack("a4", $x);
my $len  = unpack("N", "\0".substr($x, 4));

or

my ($type, $plen) = unpack("a4 a3", $x);
my $len = unpack("N", "\0$plen");



回答4:


Solution: Your method for getting the type is fine. However, I suggest that you unpack the length separately as a four-byte integer, then discard the first byte of those four bytes. This is more efficient even though it overlaps and discards the last byte of the type.

my $type = unpack("a4", $x);
my $length = unpack("x3N", $x); # skips the first 3 bytes of your original 7-byte string
$length = $length & 0xFFFFFF; # returns only the last 3 bytes of the four-byte integer


来源:https://stackoverflow.com/questions/15512295/decoding-3-byte-integer-in-perl

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!