Можете ли вы объяснить, что я получаю из распаковки? - PullRequest
5 голосов
/ 22 апреля 2011

Я относительно неопытен с Perl, но мой вопрос касается функции распаковки при получении битов для числового значения.Например:

my $bits = unpack("b*", 1);
print $bits;

Это приводит к печати 10001100, что составляет 140 в десятичном виде.В обратном порядке это 49 в десятичном виде.Любые другие значения, которые я пробовал, дают неправильные биты.

Однако, когда я запускаю $ bits через pack, он снова выдает 1.Я что-то упускаю здесь?

Кажется, я пришел к выводам, когда думал, что моя проблема решена.Может быть, я должен кратко объяснить, что я пытаюсь сделать.

Мне нужно преобразовать целочисленное значение, которое может быть размером до 24 бит (суть в том, что оно может быть больше одного байта)немного строкиЭтого можно достичь, используя unpack и pack, как предложено @ikegami, но мне также нужно найти способ преобразовать эту битовую строку обратно в ее исходное целое число (а не в ее строковое представление).упомянуто, я относительно неопытен с Perl, и я пытался безуспешно.

Я нашел то, что кажется оптимальным решением:

my $bits = sprintf("%032b", $num);
print "$bits\n";
my $orig = unpack("N", pack("B32", substr("0" x 32 . $bits, -32)));
print "$orig\n";

Ответы [ 6 ]

6 голосов
/ 22 апреля 2011

Это может быть очевидно, но другие ответы не указали на это явно: вторым аргументом в unpack("b*", 1) является приведение типа к строке "1", которая имеет значение ASCII 31 в шестнадцатеричном виде (с сначала самый значительный клев).

Соответствующий двоичный файл будет 00110001, который будет инвертирован до 10001100 в ваших выходных данных, потому что вы использовали "b*" вместо "B*". Они соответствуют противоположным «порядковым» формам двоичного представления. «Endian-ness» - это то, идут ли старшие биты в начале или в конце двоичного представления.

3 голосов
/ 22 апреля 2011

Да, вам не хватает того, что разные машины поддерживают разную «последовательность» .И Perl рассматривает 1 как '1' так (0x31).Итак, вы видите 1 -> 1000 (в порядке возрастания) и 3 -> 1100.

«Неверно» зависит от перспективы и от того, дали ли вы Perl достаточно информации, чтобы знать, какую кодировку и порядковый номер вы хотите.

От pack:

b A bit string (ascending bit order inside each byte, like vec()).
B A bit string (descending bit order inside each byte).

Я думаю, это то, что вы хотите:

unpack( 'B*', chr(1))
2 голосов
/ 22 апреля 2011

Вы пытаетесь преобразовать целое число в двоичное, а затем обратно. Хотя вы можете сделать это с помощью pack и затем unpack , лучше использовать sprintf или printf с форматом %b :

my $int = 5;
my $bits = sprintf "%024b\n", $int;
print "$bits\n";

Чтобы пойти другим путем (преобразование строки 0 и 1 в целое число), лучше всего использовать функцию oct с префиксом 0b:

my $orig = oct("0b$bits");
print "$orig\n";

Как объяснили другие, unpack ожидает, что строка будет распакована, поэтому, если у вас есть целое число, вам сначала нужно pack преобразовать ее в строку. Формат %b предполагает, что целое число должно начинаться с.

Если вам нужно сделать многое из байтов, а скорость имеет решающее значение, вы можете создать таблицу поиска:

my @binary = map { sprintf '%08b', $_ } 0 .. 255;

print $binary[$int];  # Assuming $int is between 0 and 255
2 голосов
/ 22 апреля 2011

ord(1) - это 49. Вы должны захотеть что-то вроде sprintf("%064b", 1), хотя это кажется излишним.

1 голос
/ 22 апреля 2011

Вы не указали, что вы ожидаете.Я предполагаю, что вы ожидаете 00000001.

Это правильные биты для предоставленного вами байта, по крайней мере, в не-EBCDIC системах.Помните, что вход unpack является строкой (в основном это строки байтов).Возможно, вы хотели

unpack('b*', pack('C', 1))

Обновление : как уже отмечали другие, вышеприведенное дает 10000000.Для 00000001 вы бы использовали

unpack('B*', pack('C', 1))  # 00000001
0 голосов
/ 22 апреля 2011

Вы хотите "B" вместо "b".

$ perl -E'say unpack "b*", "1"'
10001100

$ perl -E'say unpack "B*", "1"'
00110001

pack

...