如何在Perl中将十六进制解码为负整数值(第2部分)

问题描述 投票:1回答:3

我对十六进制格式的负整数值有疑问。我的工作有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。

perl integer hex
3个回答
3
投票
$num = unpack 'q', pack 'Q', $num;
是用于64位带符号的整数。对于32位值,您需要使用

$num = unpack 'l', pack 'L', $num;

$num -= 2**32;


0
投票
也许下面的代码将转换为所需的结果

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


0
投票
代码的其他变体

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

© www.soinside.com 2019 - 2024. All rights reserved.