Эндиантность целых чисел в Python
Я работаю над программой, где храню некоторые данные в целых числах и обрабатываю их поразрядным образом. Например, я могу получить число 48, которое я буду обрабатывать поэтапно. В целом, конечность целых чисел зависит от машинного представления целых чисел, но делает ли Python что-либо, чтобы гарантировать, что ints всегда будет мало-endian? Или мне нужно проверить соответствие, как я бы на C, а затем написать отдельный код для двух случаев?
Я спрашиваю, потому что мой код работает на машине Sun, и, хотя тот, на котором он работает, теперь использует процессоры Intel, мне, возможно, придется переключиться на машину с процессорами Sun в будущем, и я знаю, что это big-endian.
Ответы
Ответ 1
Python int
имеет ту же конечность, что и процессор, над которым он работает. Модуль struct
позволяет конвертировать байтовые капли в ints (и наоборот, и некоторые другие типы данных тоже) как в native, little-endian, или big-endian способами, в зависимости от строка формата, которую вы выбираете: запустите формат с помощью @
или нет символа энтитичности, чтобы использовать встроенную endianness (и собственные размеры - все остальное использует стандартные размеры), '~' для native, '<' для little-endian, ' > ' или '!' для больших стран.
Это байтовое число, а не побитовое; не уверен точно, что вы подразумеваете под побитовой обработкой в этом контексте, но я предполагаю, что он может быть размещен аналогичным образом.
Для быстрой "массовой" обработки в простых случаях рассмотрите также модуль array - методы fromstring
и tostring
может работать на большом количестве байтов быстро, а метод byteswap
может получить вас "другой" endianness (родной для не-native или наоборот), снова быстро и для большого количества элементов (весь массив).
Ответ 2
Если вам нужно обработать ваши данные "поразмерно", вам может помочь bitstring
. Он также может иметь дело с контентом между платформами (по крайней мере, по последнему строчку сборки), которые будут выпущены в ближайшие несколько дней.
Модуль struct
является наилучшим стандартным методом решения проблем между платформами. Например, пакеты упаковывают и распаковывают целые числа 1, 2, 3 на два "коротких" и один "длинный" (2 и 4 байта на большинстве платформ), используя собственную энтитичность:
>>> from struct import *
>>> pack('hhl', 1, 2, 3)
'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', '\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
Чтобы программно определить консистенцию платформы, вы можете использовать
>>> import sys
>>> sys.byteorder
который либо вернет "big"
, либо "little"
.
Ответ 3
Проверить, когда?
При выполнении побитовых операций int in будет иметь такую же endianess, что и введенные вами int. Вам не нужно это проверять. Вам нужно только об этом заботиться при преобразовании в/из последовательностей байтов на обоих языках, afaik.
В Python для этого используется структурный модуль, чаще всего struct.pack() и struct.unpack().
Ответ 4
Следующий фрагмент скажет вам, является ли ваш системный по умолчанию малозначимым (в противном случае это big-endian)
import struct
little_endian = (struct.unpack('<I', struct.pack('=I', 1))[0] == 1)
Обратите внимание, что это не повлияет на поведение побитовых операторов: 1<<1
равно 2
, независимо от стандартности по умолчанию вашей системы.