I have an array and each item in the array is an array of 2 numbers the values of which are in the range of 16 bits.
For each item in the array I need to place these 2 numbers inside a 32 bit integer and then save it in a table in a MySQL database in a column of type varbinary
.
I think I need to use pack
with template S!
to create one 32 bit integer containing the other 2 numbers in the upper/lower 16 bits.
I think I need to use pack
with template I!
for creating the final value to be saved in the database.
But I am not sure how I can do that with pack
and I don't really understand the example in the doc about how to form a loop.
my( $ip, $cs,
$flags,$fl,$fh,
$ax,$al,$ah, $bx,$bl,$bh, $cx,$cl,$ch, $dx,$dl,$dh,
$si, $di, $bp, $ds, $es ) =
unpack( 'v2' . ('vXXCC' x 5) . 'v5', $frame );
Could someone please help with how can I use pack
for implementing this? Or is pack
not the right solution for both cases?
For instance for creating one 32 bit number the following snippet:
my $number1 = 120;
my $number2 = 3090;
my $word = pack( 'S!*S!*', $number1, $number2 );
print "$word \n";
prints: x
I was expecting that it would print 1 number (32 bit integer). What am I doing wrong/misunderstanding here?
Update after @ikegami comment:
- 32-bit integer
- $number1 is the high order bits
- Big endian
Update 2 after @ikegami comments. I tried the following:
my @array = (
[120, 3090],
[34, 2018],
[47, 4005],
[98, 2345],
[111, 1]
);
my @packed;
foreach ( @array ) {
my @elem = $_;
print $elem[0][0]. " - ". $elem[0][1]. "\n";
my $id = $elem[0][0];
my $num = $elem[0][1];
my $word = pack( 'S>2', $id, $num);
push @packed, $word;
say sprintf "%v02X", $word;
}
my $packed_output = pack('I*', @packed); // line 63
say sprintf "%v02X", $packed_output;
This fails with the following print:
00.78.0C.12
120 - 3090
00.78.0C.12
34 - 2018
00.22.07.E2
47 - 4005
00.2F.0F.A5
98 - 2345
00.62.09.29
111 - 1
00.6F.00.01
Argument "\0x\f^R" isn't numeric in pack at line 63.
Argument "\0"^G?" isn't numeric in pack at line 63.
Argument "\0/^O?" isn't numeric in pack at line 63.
Argument "\0b^I)" isn't numeric in pack at line 63.
Argument "\0o\0^A" isn't numeric in pack at line 63.
00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00
CodePudding user response:
Close.
The double *
makes no sense. S!*S!*
should be S!*
, S!S!
or S!2
.
S!
is wrong. That refers to an unsigned int
, which is at least 16-bits, but it can vary. You want exactly 16-bit, so that should be S
.
You also didn't specify the byte order. Since you want big-ending byte order, you actually want S>
(or n
).
my $packed = pack( "S>2", $number1, $number2 ); # "\x00\x78\x0C\x12"
say sprintf "%v02X", $packed; # 00.78.0C.12
As you can see, this produces a string of four bytes rather than a number. But that is what you want. VARBINARY is used to store a sequence of bytes. Unpacking the string of bytes using using L>
gets the 32-bit number.
This brings up an alternative. You could also compute the 32-bit number and pack that.
my $packed = pack( "L>", $number1 << 16 | $number2 ); # "\x00\x78\x0C\x12"
say sprintf "%v02X", $packed; # 00.78.0C.12
Reference: Formats for Packing and Unpacking Numbers