2015-10-11 4 views
3

Я хочу кодировать числа в N бит-контейнерах и отправлять их в UDP-пакет. Приемник будет знать, N, и приемник будет захватывать число от ровно N битов (N < = 64)Perl: пакет int для произвольной длины байтовой строки

Somethink как это:.

sub to56BIT { 
    return pack("??", shift); 
} 

sub to24BIT { 
    return pack("??", shift); 
} 

my $n = 7; 
to24BIT($n); 

на стороне приемника:

int n = Get_val24(byte_stream, offset); 

Есть ли способ сделать это в Perl?

Я думаю, что решение может быть:

sub packIntN { 
     my $int = shift; 
     my $length = shift; 
     return pack("B" . $length, substr(unpack("B64", pack("Q>", $int)), 64 - $length)); 
} 

Но, может быть, есть более элегантный способ.

ввода/вывода Пример: У нас есть сценарий test.pl:

use strict; 
use warnings; 

sub to24BIT { 
     #??? 
} 

my $n = 7; 

print to24BIT($n); 

Я хочу это:

./test.pl | hexdump -C 
00000000 00 00 07           |...| 
00000003 

Другой сценарий test2.pl:

use strict; 
use warnings; 

sub to40BIT { 
     #??? 
} 

my $n = 7; 

print to40BIT($n); 

I хочу этого:

./test.pl | hexdump -C 
00000000 00 00 00 00 07         |.....| 
00000005 
+0

Можете ли вы представить пример ввода/вывода? – melpomene

+0

@melpomene, конечно. Я добавил пример. – peroksid

+0

Является ли N всегда целым множителем 8? (Один из 8, 16, 24, 32, 40, 48, 56, 64) – ikegami

ответ

3

Является ли N всегда целым множителем 8 (один из 8, 16, 24, 32, 40, 48, 56, 64)? Если это так, для скорости я рекомендую писать упаковщик для каждого размера и использовать таблицу отправки, чтобы найти нужный упаковщик.

sub pack_8bit {  pack('C', $_[0])  } 
sub pack_16bit {  pack('S>', $_[0])  } 
sub pack_24bit { substr(pack('L>', $_[0]), 1) } 
sub pack_32bit {  pack('L>', $_[0])  } 
sub pack_40bit { substr(pack('Q>', $_[0]), 3) } 
sub pack_48bit { substr(pack('Q>', $_[0]), 2) } 
sub pack_56bit { substr(pack('Q>', $_[0]), 1) } 
sub pack_64bit {  pack('Q>', $_[0])  } 

{ 
    my %packers = (
     8 => \&pack_8bit, 40 => \&pack_40bit, 
     16 => \&pack_16bit, 48 => \&pack_48bit, 
     24 => \&pack_24bit, 56 => \&pack_56bit, 
     32 => \&pack_32bit, 64 => \&pack_64bit, 
    ); 

    sub pack_num { 
     my $packer = $packers{$_[0]} 
     or die; 
     return $packer->($_[1]); 
    } 

    sub get_packer { 
     my $packer = $packers{$_[0]} 
     or die; 
     return $packer; 
    } 
} 

my $packed = pack_num(40, 7); 
    -or- 
my $packer = get_packer(40); 
my $packed = $packer->(7); 

Если вы планируете на упаковке нескольких номеров в одну строку (например, pack('L>*', @nums)), я бы также использовать таблицу отправки, как это, хотя я не уверен, что будет самым быстрым реализация pack_24bit, pack_40bit, pack_48bit и pack_56bit (кроме решения C).

2

Принимая во внимание, что вы всегда будете иметь целый число байтов, я закончил с

substr(pack("Q>",$n<<(64-$len)),0,($len+7)/8); 

и

unpack("Q>",$s.(0 x 8)) >> (64-$len); 

, как попытался в этом примере:

#!/usr/bin/perl 
$len = 40; 
$n = 7; 
$s = substr(pack("Q>",$n<<(64-$len)),0,($len+7)/8); 
open(PIPE,"| hexdump -C"); 
print PIPE $s; 
close PIPE; 

$v = unpack("Q>",$s.(0 x 8)) >> (64-$len); 
printf "%d\n",$v;