Perl: как извлечь определенные биты из байта, а затем скрыть эти биты до шестнадцатеричного значения?

мне нужно извлечь определенные биты байта и скрыть биты извлечения обратно в шестнадцатеричное значение.

пример (значение байта равно 0xD2):

76543210 bit position
11010010 is 0xD2
  • бит 0-3 определяет канал что это 0010b is 0x2
  • бит 4-5 определяет контроллер что это 01b is 0x1
  • бит 6-7 определяет порт что это 11b is 0x3

мне как-то нужно получить от байта 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