Как распаковать (64-битный) unsigned long в 64-битный Perl? - PullRequest
3 голосов
/ 30 марта 2011

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

Известно, что значение верное (я сделал тест, который отправляет одно и то же значение в две очереди, одну читает Perl, а другую приложение C), и все предшествующие значения читаются правильно (используется q вместо i! для работы с 64-битными целыми числами).

Также известно, что в PHP было что-то похожее в ошибках (поиск "unsigned long на 64-битных машинах") (похоже, похоже: Упаковать / распаковать 64-битное int на 64-битной архитектуре в PHP )

Аргументы, проверенные до сих пор:

  • .. Q (= некоторое значение больше ожидаемого)
  • .. L (= 0)
  • .. L! (= большое значение)
  • .. l (= 0)
  • .. л! (= большое значение)
  • .. Л.Н.! (= 0)
  • .. N, ..N! (= 0)

use bigint; use bignum; - без эффекта.

подробности:

  • sizeof(unsigned long) = 8;
  • Data::Dumper->new([$thatstring])->Useqq(1)->Dump(); много нулевых байтов вместе с некоторыми значащими ..
  • = порядком байтов '12345678';

Решение: - x4Q с заполнением четырьмя байтами.

Ответы [ 2 ]

3 голосов
/ 30 марта 2011

Распаковка с использованием Q в шаблон работает из коробки, если у вас есть 64-битный Perl:

The TEMPLATE is a sequence of characters that give the order
and type of values, as follows:

 ...

 q   A signed quad (64-bit) value.
 Q   An unsigned quad value.
       (Quads are available only if your system supports 64-bit
        integer values _and_ if Perl has been compiled to support those.
        Causes a fatal error otherwise.)

Для более надежного решения распакуйте значение в8-байтовая строка и использовать модуль Math::Int64 для преобразования ее в целое число:

use Math::Int64 qw( :native_if_available int64 );

...

$string_value = unpack("A8", $longint_from_the_C_program);

# one of these two functions will work, depending on your system's endian-ness
$int_value = Math::Int64::native_to_int64($string_value);
$int_value = Math::Int64::net_to_int64($string_value);
1 голос
/ 30 марта 2011

Решение было простым: добавлено x4Q, чтобы пропустить четыре байта до фактического значения;надо больше визуально подумать о набивке / выравнивании ..

...