我对十六进制格式的负整数值有疑问。我的工作有2种格式,如下例所示:
###########################################################################
=for comment
B4 80 B5 FF 07 = 2146254900
B5 80 B5 FF 07 = 2146254901
A9 B4 E8 8C 08 = -2120607191
AA B4 E8 8C 08 = -2120607190
A3 86 8D 8E FC FF FF FF FF 01 = -1044167901
A4 86 8D 8E FC FF FF FF FF 01 = -1044167900
=cut
###########################################################################
$vars[0] = "\xB4\x80\xB5\xFF\x07";
$vars[1] = "\xB5\x80\xB5\xFF\x07";
$vars[2] = "\xA9\xB4\xE8\x8C\x08";
$vars[3] = "\xAA\xB4\xE8\x8C\x08";
$vars[4] = "\xA3\x86\x8D\x8E\xFC\xFF\xFF\xFF\xFF\x01";
$vars[5] = "\xA4\x86\x8D\x8E\xFC\xFF\xFF\xFF\xFF\x01";
###########################################################################
for my $var (@vars)
{
print decodeInt($var) . "\n";
}
###########################################################################
sub decodeInt
{
$_[0] =~ s/^([\x80-\xFF]*[\x00-\x7F])// or return;
my $encoded_num = $1;
my $num = 0;
for ( reverse unpack 'C*', $encoded_num )
{
$num = ( $num << 7 ) | ( $_ & 0x7F );
}
$num = unpack 'q', pack 'Q', $num; #Cast two unsigned complement Ints back to 64-bit signed
return $num;
}
##########################################################################
以前,以上代码运行良好。但是现在我有了负整数值的新格式,该格式不起作用。
A9 B4 E8 8C 08 = -2120607191
AA B4 E8 8C 08 = -2120607190
我的代码解码为2174360105和2174360106。
$num = unpack 'q', pack 'Q', $num;
是用于64位带符号的整数。对于32位值,您需要使用
$num = unpack 'l', pack 'L', $num;
或
$num -= 2**32;
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my $debug = 0;
while( my $num = <DATA> ) {
chomp $num;
say hex2dec($num);
}
sub hex2dec {
my $data = shift;
my $sign = 0;
my $num = 0;
my $bits;
my @data = reverse split ' ', $data;
$bits = 32 if scalar @data == 5;
$bits = 64 if scalar @data == 10;
map { $num = ($num << 7)|h2i($_) } @data;
$sign = ($num & (1<<($bits-1)) ) ? 1 : 0;
if( $debug ) {
say Dumper(\@data);
say "bits : $bits";
say "sign : $sign";
say "num : $num";
num2bin( $num,$bits);
num2bin(~$num,$bits);
}
if( $sign ) {
$num = -1 * ((1<<$bits) - $num) if $bits == 32;
$num = -1 * (~$num + 1) if $bits == 64;
}
return $num;
}
# Hex byte to integer number
sub h2i {
my $data = shift;
my $r = 0;
my %hex2dec;
@hex2dec{0..9,'A'..'F'} = 0..15;
map { $r <<= 4; $r += $hex2dec{$_} } split '', $data;
return $r&0x7F;
}
# Print integer number as bin
sub num2bin {
my $num = shift;
my $bit = shift;
my $bin;
while( $bit-- ) {
$bin .= $num & (1<<$bit) ? '1' : '0';
}
say $bin;
}
=for comment
B4 80 B5 FF 07 = 2146254900
B5 80 B5 FF 07 = 2146254901
A9 B4 E8 8C 08 = -2120607191
AA B4 E8 8C 08 = -2120607190
A1 E1 CE FD 0F = -5001055
A3 86 8D 8E FC FF FF FF FF 01 = -1044167901
A4 86 8D 8E FC FF FF FF FF 01 = -1044167900
=cut
__DATA__
B4 80 B5 FF 07
B5 80 B5 FF 07
A9 B4 E8 8C 08
AA B4 E8 8C 08
A1 E1 CE FD 0F
A3 86 8D 8E FC FF FF FF FF 01
A4 86 8D 8E FC FF FF FF FF 01
输出
2146254900 2146254901 -2120607191 -2120607190 -5001055 -1044167901 -1044167900
use strict;
use warnings;
use feature 'say';
use bytes;
my $debug = 1;
my @vars = ( "\xB4\x80\xB5\xFF\x07",
"\xB5\x80\xB5\xFF\x07",
"\xA9\xB4\xE8\x8C\x08",
"\xAA\xB4\xE8\x8C\x08",
"\xA1\xE1\xCE\xFD\x0F",
"\xA3\x86\x8D\x8E\xFC\xFF\xFF\xFF\xFF\x01",
"\xA4\x86\x8D\x8E\xFC\xFF\xFF\xFF\xFF\x01"
);
foreach my $v (@vars) {
say 'DATA : '
. decode($v)
. ' :: '
. unpack 'H'. bytes::length($v)*2, $v;
}
sub decode {
my $data = shift;
my $num = 0;
my $bits;
my $ret;
map { $num = ($num << 7) | ($_ & 0x7F) } reverse unpack 'C*', $data;
my $bytes = bytes::length($num);
$bits = 32 if $bytes == 10;
$bits = 64 if $bytes == 20;
my $sign = $num & (1<<($bits-1)) ? 1 : 0;
if( $sign ) {
$ret = -1 * ((1<<$bits) - $num) if $bits == 32;
$ret = -1 * (~$num + 1) if $bits == 64;
} else {
$ret = $num;
}
if( $debug ) {
say "\nDebug\n" . '-' x 20;
say "data : " . unpack 'H'. $bytes, $data;
say "bytes : $bytes";
say "num : $num (dec)";
say "bits : $bits";
say "sign : $sign";
say "hex : " . itoh($num);
say "bin : " . num2bin( $num, $bits);
say "~bin : " . num2bin(~$num, $bits);
say "decode : $ret";
}
return $ret;
}
# Print integer number as bin
sub num2bin {
my $num = shift;
my $bit = shift;
my $bin;
while( $bit-- ) {
$bin .= $num & (1<<$bit) ? '1' : '0';
}
return $bin;
}
# Convert integer to ascii hex
sub itoh {
my $data = shift;
my $hex;
my %hex;
@hex{0..15} = (0..9,'A'..'F');
while( $data ) {
my $n = $data & 0xF;
$data >>= 4;
$hex .= $hex{$n};
}
return reverse $hex;
}
输出
Debug -------------------- data : b480b5ff07 bytes : 10 num : 2146254900 (dec) bits : 32 sign : 0 hex : 7FED4034 bin : 01111111111011010100000000110100 ~bin : 10000000000100101011111111001011 decode : 2146254900 DATA : 2146254900 :: b480b5ff07 Debug -------------------- data : b580b5ff07 bytes : 10 num : 2146254901 (dec) bits : 32 sign : 0 hex : 7FED4035 bin : 01111111111011010100000000110101 ~bin : 10000000000100101011111111001010 decode : 2146254901 DATA : 2146254901 :: b580b5ff07 Debug -------------------- data : a9b4e88c08 bytes : 10 num : 2174360105 (dec) bits : 32 sign : 1 hex : 819A1A29 bin : 10000001100110100001101000101001 ~bin : 01111110011001011110010111010110 decode : -2120607191 DATA : -2120607191 :: a9b4e88c08 Debug -------------------- data : aab4e88c08 bytes : 10 num : 2174360106 (dec) bits : 32 sign : 1 hex : 819A1A2A bin : 10000001100110100001101000101010 ~bin : 01111110011001011110010111010101 decode : -2120607190 DATA : -2120607190 :: aab4e88c08 Debug -------------------- data : a1e1cefd0f bytes : 10 num : 4289966241 (dec) bits : 32 sign : 1 hex : FFB3B0A1 bin : 11111111101100111011000010100001 ~bin : 00000000010011000100111101011110 decode : -5001055 DATA : -5001055 :: a1e1cefd0f Debug -------------------- data : a3868d8efcffffffff01 bytes : 20 num : 18446744072665383715 (dec) bits : 64 sign : 1 hex : FFFFFFFFC1C34323 bin : 1111111111111111111111111111111111000001110000110100001100100011 ~bin : 0000000000000000000000000000000000111110001111001011110011011100 decode : -1044167901 DATA : -1044167901 :: a3868d8efcffffffff01 Debug -------------------- data : a4868d8efcffffffff01 bytes : 20 num : 18446744072665383716 (dec) bits : 64 sign : 1 hex : FFFFFFFFC1C34324 bin : 1111111111111111111111111111111111000001110000110100001100100100 ~bin : 0000000000000000000000000000000000111110001111001011110011011011 decode : -1044167900 DATA : -1044167900 :: a4868d8efcffffffff01