/ / Jak rozpakować (64-bit) bez znaku długi w 64-bitowym pliku Perl? - perl, 64bit, rozpakuj

Jak rozpakować (64-bit) bez znaku długi w 64-bitowym pliku Perl? - perl, 64bit, rozpakuj

Próbuję rozpakować niepodpisaną długą wartość, która jest przekazywana z programu C do skryptu Perla przez SysV :: IPC.

Wiadomo, że wartość jest poprawna (zrobiłem atest, który wysyła tę samą wartość do dwóch kolejek, jednej czytanej przez Perla, a drugiej przez aplikację C), a wszystkie poprzednie wartości są odczytywane poprawnie (używane q zamiast i! do pracy z 64-bitowymi liczbami całkowitymi).

Wiadomo również, że PHP miał coś podobnego w błędach (szukaj "unsigned long on 64 bit machines") (wydaje się być podobne: Spakuj / rozpakuj 64-bitowe int w architekturze 64-bitowej w PHP)

Argumenty przetestowane do tej pory:

  • ..Q (= pewna wartość większa niż oczekiwano)
  • ..L (= 0)
  • ..L! (= duża wartość)
  • ..l (= ​​0)
  • ..l! (= duża wartość)
  • ..lN! (= 0)
  • ..N, ..N! (= 0)

use bigint; use bignum; -- bez efektu.

Detale:

  • sizeof(unsigned long) = 8;
  • Data::Dumper->new([$thatstring])->Useqq(1)->Dump(); wiele bajtów o wartościach null w niektórych znaczących ...
  • byteorder = "12345678";

Rozwiązanie: - x4Q z dopełnieniem czterech bajtów.

Odpowiedzi:

3 dla odpowiedzi № 1

Rozpakowywanie za pomocą Q w szablon działa po wyjęciu z pudełka, jeśli masz 64-bitowy 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.)

Aby uzyskać bardziej niezawodne rozwiązanie, rozpakuj wartość na 8-bajtowy łańcuch i użyj znaku Math::Int64 moduł do przekonwertowania go na liczbę całkowitą:

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 dla odpowiedzi nr 2

Rozwiązanie było proste: dodano x4Q aby pominąć cztery bajty przed rzeczywistą wartością; trzeba bardziej wizualnie myśleć o wyściełaniu / wyrównaniu.