Подтвердить что ты не робот

Разница между различными шестнадцатеричными типами/представлениями в Python

Работая над некоторым кодом Python, я замечаю, что для шестнадцатеричных значений существует несколько разных представлений. Например, если я выберу такое число:

xx = '\x03\xff'

Затем следующая команда (версия которой я использую для преобразования little endian в big endian)

yy = hex(struct.unpack('>H', xx)[0])

вернется:

'0x3ff'

Однако эта команда

zz = xx.encode('hex')

вернется:

'03ff'

Наконец, печать только значения вне этого возвращает

'\x03\xff'

По внешнему виду есть три разных типа гекса.

  • '\xFF'
  • '0xFF'
  • 'FF'

Какая разница?

Бонусные очки, если кто-то может предложить лучший способ преобразования маленького числа endian в большое число endian. Вышеуказанный метод для yy не будет работать для чисел, превышающих два байта, упрямо, и я работаю с шестнадцатеричными строками длиной 16 байт (включая значения, которые не соответствуют значению ascii/integer)

4b9b3361

Ответ 1

Все, что использует \x, - это код escape строки, который используется для использования шестнадцатеричной нотации; другие escape-коды включают \n для строк новой строки, \' для литеральной цитаты и т.д. Строка python представляет собой последовательность байтов, и вы можете указать литеральные значения вне диапазона печати ASCII с использованием таких символов. Когда Python повторяет строковое значение на вас в интерпретаторе или вы печатаете результат вызова repr() на строку, Python будет использовать такие escape-последовательности для представления любого байта, который не может быть напечатан как символ ASCII вместо:

>>> chr(65)
'A'
>>> chr(11)
'\x0b'

Функция hex() возвращает очень специфическое строковое представление, равно как и .encode('hex') с той разницей, что первая включает префикс 0x. Существует два способа создания таких строковых представлений; используя форматы '%x' и '%x', в которых для представления используются строчные или прописные буквы.

>>> hex(11)
'0xb'
>>> '\x0b'.encode('hex')
'0b'
>>> '%x' % (11,)
'b'
>>> '%X' % (11,)
'B'

Это все строковые представления, хотя (серия символов ASCII) и имеют то же отношение к исходным данным, что и str(number) - к целочисленным данным; вы изменили тип и дальше от цели изменения порядка байтов.

Изменение части бинарной информации от маленького конца до big-endian требует, чтобы вы знали размер этой части информации. Если у вас есть короткие целые числа, вам нужно перевернуть каждые два байта, но если у вас нормальные (длинные) целые числа, то у вас есть 4 байта на одно значение, и вам нужно отменить каждый 4 байта.

Использование модуля struct, я считаю, отличным подходом, потому что вы должны указать тип значения. Следующее интерпретировало бы xx как бинарный конец unsigned short int, а затем упаковывает его обратно в двоичное представление в виде малознакового числа без знака short int:

>>> import struct
>>> xx = '\x03\xff'
>>> struct.pack('<H', *struct.unpack('>H', xx))
'\xff\x03'

Ответ 2

'\ xFF' представляет строку, содержащую символ с кодом ASCII 255.

т.д.: print '\x41' дает "A" (потому что это символ с кодом ASCII 41)

xx.encode('hex') и hex(struct.unpack('>H', xx)[0]) просто дают человекообразное шестнадцатеричное представление кодов ASCII, содержащее строку xx. Это означает, что результирующая строка содержит несколько символов между а и f или 0 и 9.