问题
I'm trying to unpack an unsigned long value that is passed from a C program to a Perl script via SysV::IPC.
It is known that the value is correct (I made a test which sends the same value into two queues, one read by Perl and the second by the C application), and all predecessing values are read correctly (used q
instead of i!
to work with 64-bit integers).
It is also known that PHP had something similar in bugs (search for "unsigned long on 64 bit machines") (seems to be similar: Pack / unpack a 64-bit int on 64-bit architecture in PHP)
Arguments tested so far:
- ..Q ( = some value that is larger than expected)
- ..L ( = 0)
- ..L! ( = large value)
- ..l ( = 0)
- ..l! ( = large value)
- ..lN! ( = 0)
- ..N, ..N! ( = 0)
use bigint; use bignum;
-- no effect.
Details:
sizeof(unsigned long)
= 8;Data::Dumper->new([$thatstring])->Useqq(1)->Dump();
a lot of null bytes along some meaningful..- byteorder='12345678';
Solution:
- x4Q
with padding four bytes.
回答1:
Unpacking using Q
in the template works out of the box if you have 64-bit Perl:
The TEMPLATE is a sequence of characters that give the order
and type of values, as follows:
...
q A signed quad (64-bit) value.
Q An unsigned quad value.
(Quads are available only if your system supports 64-bit
integer values _and_ if Perl has been compiled to support those.
Causes a fatal error otherwise.)
For a more robust solution, unpack the value into an 8-byte string and use the Math::Int64 module to convert it to an integer:
use Math::Int64 qw( :native_if_available int64 );
...
$string_value = unpack("A8", $longint_from_the_C_program);
# one of these two functions will work, depending on your system's endian-ness
$int_value = Math::Int64::native_to_int64($string_value);
$int_value = Math::Int64::net_to_int64($string_value);
回答2:
The solution was simple: added x4Q
to skip four bytes before actual value; need to more visually think of padding/alignment..
来源:https://stackoverflow.com/questions/5488551/how-to-unpack-64-bit-unsigned-long-in-64-bit-perl