У меня есть массив, и каждый элемент массива представляет собой массив из двух чисел, значения которых находятся в диапазоне 16 бит.
Для каждого элемента в массиве мне нужно поместить эти 2 числа в 32-битное целое число, а затем сохранить его в таблице в базе данных MySQL в столбце типа varbinary
.
Я думаю, мне нужно использовать pack
с шаблоном S!
, чтобы создать одно 32-битное целое число, содержащее 2 других числа в старших/младших 16 битах.
Я думаю, что мне нужно использовать pack
с шаблоном I!
для создания окончательного значения, которое будет сохранено в базе данных.
Но я не уверен, как я могу сделать это с pack
, и я не очень понимаю пример в doc о том, как сформировать петлю.
my( $ip, $cs,
$flags,$fl,$fh,
$ax,$al,$ah, $bx,$bl,$bh, $cx,$cl,$ch, $dx,$dl,$dh,
$si, $di, $bp, $ds, $es ) =
unpack( 'v2' . ('vXXCC' x 5) . 'v5', $frame );
Может ли кто-нибудь помочь с тем, как я могу использовать pack
для реализации этого? Или pack
не подходит для обоих случаев?
Например, для создания одного 32-битного числа следующий фрагмент:
my $number1 = 120;
my $number2 = 3090;
my $word = pack( 'S!*S!*', $number1, $number2 );
print "$word \n";
принты: x
Я ожидал, что он напечатает 1 число (32-битное целое число). Что я делаю неправильно/не понимаю здесь?
Обновление после комментария @ikegami:
Обновление 2 после комментариев @ikegami. Я пробовал следующее:
my @array = (
[120, 3090],
[34, 2018],
[47, 4005],
[98, 2345],
[111, 1]
);
my @packed;
foreach ( @array ) {
my @elem = $_;
print $elem[0][0]. " - ". $elem[0][1]. "\n";
my $id = $elem[0][0];
my $num = $elem[0][1];
my $word = pack( 'S>2', $id, $num);
push @packed, $word;
say sprintf "%v02X", $word;
}
my $packed_output = pack('I*', @packed); // line 63
say sprintf "%v02X", $packed_output;
Это не удается со следующей печатью:
00.78.0C.12
120 - 3090
00.78.0C.12
34 - 2018
00.22.07.E2
47 - 4005
00.2F.0F.A5
98 - 2345
00.62.09.29
111 - 1
00.6F.00.01
Argument "\0x\f^R" isn't numeric in pack at line 63.
Argument "\0"^G?" isn't numeric in pack at line 63.
Argument "\0/^O?" isn't numeric in pack at line 63.
Argument "\0b^I)" isn't numeric in pack at line 63.
Argument "\0o\0^A" isn't numeric in pack at line 63.
00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00
Два *
неверны. S!*S!*
это то же самое, что просто S!*
, чего достаточно,
Re «Я ожидал, что он напечатает 1 число», нет, он выдает строку байтов. Но это на самом деле то, что вы хотите.
В этом вопросе отсутствует много информации. 1) Это 32-битное целое число со знаком или без знака? 2) Является ли $number1
или $number2
старшими битами? 3) Какой порядок следования байтов следует использовать (собственный, прямой или прямой)?
@ikegami: 1) 32-битное целое число без знака 2) $number1
- это самые значащие биты 3) прямой порядок байтов
@ikegami: как unsigned short
может быть больше 16 бит?
C только гарантирует, что unsigned short будет как минимум -32767..32767
Закрывать.
Двойной *
не имеет смысла. S!*S!*
должно быть S!*
, S!S!
или S!2
.
S!
неправильно. Это относится к unsigned int
, который имеет длину не менее 16 бит, но может варьироваться. Вы хотите именно 16-бит, так что должно быть S
.
Вы также не указали порядок байтов. Поскольку вам нужен порядок байтов с большим концом, вам действительно нужен S>
(или n
).
my $packed = pack( "S>2", $number1, $number2 ); # "\x00\x78\x0C\x12"
say sprintf "%v02X", $packed; # 00.78.0C.12
Как видите, получается строка из четырех байтов, а не число. Но это то, что вы хотите. VARBINARY используется для хранения последовательности байтов. При распаковке строки байтов с помощью L>
получается 32-битное число.
Это вызывает альтернативу. Вы также можете вычислить 32-битное число и упаковать его.
my $packed = pack( "L>", $number1 << 16 | $number2 ); # "\x00\x78\x0C\x12"
say sprintf "%v02X", $packed; # 00.78.0C.12
Ссылка: Форматы упаковки и распаковки номеров
Комментарии не для расширенного обсуждения; этот разговор был перемещен в чат.
S!
неправильно. Вам нужны ровно два 16-битных целых числа, а не дваunsigned short
(которые имеют размер не менее 16 бит, но могут быть и больше)