Ruby: Почему распаковка ('Q') дает результат, отличный от ручного преобразования? - PullRequest
0 голосов
/ 29 апреля 2018

Я пытаюсь написать функцию, которая будет .unpack('Q') (распаковывать в uint64_t) без доступа к методу распаковки.

Когда я вручную преобразовываю строку в двоичный файл в uint64, я получаю результат, отличный от .unpack('Q'):

Integer('abcdefgh'.unpack('B*').first, 2) # => 7017280452245743464

'abcdefgh'.unpack('Q').first # => 7523094288207667809

Я не понимаю, что здесь происходит.

Я также не понимаю, почему вывод .unpack('Q') фиксирован независимо от размера ввода. Если я добавлю тысячу символов после 'abcdefgh' и затем распакую ('Q'), я все равно просто получу [7523094288207667809]?

1 Ответ

0 голосов
/ 29 апреля 2018

Порядок байтов имеет значение:

 Integer('abcdefgh'.
           each_char.
           flat_map { |c| c.unpack('B*') }.
           reverse.
           join, 2)
 #⇒ 7523094288207667809
 'abcdefgh'.unpack('Q*').first
 #⇒ 7523094288207667809

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


В последней части вашего вопроса причина того, что вывод .unpack('Q') не изменяется с более длинной входной строкой, заключается в том, что формат задает одно 64-битное значение, поэтому любые символы после первых 8 игнорируются. Если вы указали формат Q2 и строку из 16 символов, вы бы декодировали 2 значения:

> 'abcdefghihjklmno'.unpack('Q2')
=> [7523094288207667809, 8029475498074204265]

и снова вы обнаружите, что добавление дополнительных символов не изменит результат:

> 'abcdefghihjklmnofoofoo'.unpack('Q2')
=> [7523094288207667809, 8029475498074204265]

Формат Q* вернул бы столько значений, сколько было кратно 64-битным на входе:

> 'abcdefghihjklmnopqrstuvw'.unpack('Q*')
=> [7523094288207667809, 8029475498074204265, 8608196880778817904]
> 'abcdefghihjklmnopqrstuvwxyz'.unpack('Q*')
=> [7523094288207667809, 8029475498074204265, 8608196880778817904]
...