Perl: как извлечь определенные биты из байта, а затем скрыть эти биты до шестнадцатеричного значения?
мне нужно извлечь определенные биты байта и скрыть биты извлечения обратно в шестнадцатеричное значение.
пример (значение байта равно 0xD2):
76543210 bit position
11010010 is 0xD2
- бит 0-3 определяет канал что это
0010b
is0x2
- бит 4-5 определяет контроллер что это
01b
is0x1
- бит 6-7 определяет порт что это
11b
is0x3
мне как-то нужно получить от байта 0xD2
на канале 0x2
, контролер 0x1
, порт 0x3
я погуглил allot и нашел функции pack
/unpack
, vec
и sprintf
. Но я чешу голову, как использовать функции для достижения этого. Есть идеи, как достичь этого в Perl ?
2 ответов
каков первоначальный формат?
my $chr = chr(0b11010010); # e.g. from read()
my $bin = '11010010';
my $num = 0b11010010;
вы хотите начать с преобразования его в число
my $num = ord($chr);
my $num = unpack('C', $chr); # Alternative
my $num = oct("0b$bin");
затем вы используете смены и маски.
my $channel = ($num >> 0) & 0xF; # Or just: $num & 0xF
my $controller = ($num >> 4) & 0x3;
my $port = ($num >> 6) & 0x3; # Or just: $num >> 6
(вы можете использовать 0b1111
, 0b11
и 0b11
для масок. Большинство людей работают в hex.)
или пусть vec
выяснить маски для вас.
my $channel = vec $num, 0, 4;
my $controller = vec $num, 4, 2;
my $port = vec $num, 6, 2;
вот пример $controller
:
11010010
>> 4
--------
11010010
& 11
--------
01
(какие нули опущены для ясности.)
vec
- хороший выбор. Я думаю, что это довольно просто:
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
my @channels = map "channel_$_" => 0 .. 15;
my @controllers = map "controller_$_" => 0 .. 3;
my @ports = map "port_$_" => 0 .. 3;
my $bits = 0b11010010;
my $channel = vec $bits, 0, 4;
my $controller = vec $bits, 4, 2;
my $port = vec $bits, 6, 2;
say "channel : $channels[$channel]";
say "controller : $controllers[$controller]";
say "port : $ports[$port]";
выход:
channel : channel_2
controller : controller_1
port : port_3