Начинающим: что такое Big-Endian и Little-Endian
Знаю, что для начинающих разработчиков часто такая простая, вроде бы, вещь, как "порядок байтов" становится просто наказанием.
И даже знаю, почему... Пока мы работаем с байтами все вполне однозначно, но стоит перейти к словам, либо двойным словам, могут начаться "странности". Вроде бы нужно передать слово 0x1234. В эмуляторе разработчик видит 0x1234, переменную в отладчике ему показывают 0x1234 и все хорошо. Включаем прямой доступ к памяти, запускаем передачу... и принимаем на другом конце 0x3412.
И в институте, вроде, учили про Big-Endian и Little-Endian, да кто же вспоминает, чему там учили...
Всегда надо учитывать порядок данных при передаче от одного процессора к другому, иначе они банально могут друг-друга не понять, либо понять неверно.
Порядок от старшего к младшему (Big-endian)
Это привычный нам порядок записи. Слово 0x1234 будет храниться в памяти как два последовательных байта 0x12 0x34.
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
Длинное слово 0x12345678 будет лежать в памяти следующим образом: 0x12 0x34 0x56 0x78.
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
Такой порядок байт используется в TCP/IP, процессорах SPARC и 68k.
Порядок от младшего к старшему (Little-Endian)
При хранении данных в памяти в Little-Endian слово 0x1234 расположится в памяти так: 0x34 0x12.
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
Обратите внимание, что порядок бит в байте не меняется, так же как и порядок ниблов!!
Длинное слово 0x12345678 будет лежать в памяти следующим образом: 0x78 0x56 0x34 0x12.
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 |
0 | 1 | 0 | 0 | 0 | 0 | 1 | 1 |
0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
То есть самый старший байт лежит по последнему байтовому адресу. Это необходимо учитывать, если Вы пытаетесь получить данные через указатели разных типов.
Например, банальный код
Код C:unsigned char endian[2] = {1, 0}; short x; x = *(short *) endian;
Little-Endian характерен для USB, PCI, а также процессоров x86 и VAX.
Смешанный порядок (Middle-Endian)
Сами слова в пределах длинного слова могут лежать от старшего к младшему, однако в пределах слова используется порядок от младшего к старшему.
Двухбайтовое слово хранится аналогично Big Endian.
То есть длинное слово 0x12345678 будет представлено в памяти как гибрид Big Endian и Little Endian 0x34 0x12 0x78 0x56.
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 |
0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 |
Такой порядок использовался в PDP-11, есть ли на данный момент процессоры, использующие этот порядок расположения байт, мне не известно.
Некоторые процессоры (ARM, PowerPC) умеют работать с разным порядком байт, и его можно задать при конфигурировании процессора.
Как писать хорошо переносимый код?
Естественный вопрос: как писать такой код, который не придется переписывать под каждую конкретную архитектуру процессора? Может ли программа сама определять порядок байт?
Да, может! И все давно придумано до нас. Приведу несколько примеров от IBM.
Пример 1
Код C:const int i = 1; #define is_bigendian() ( (*(char*)&i) == 0 ) int main(void) { int val; char *ptr; ptr = (char*) &val; val = 0x12345678; if (is_bigendian()) { printf("%X.%X.%X.%X\n", u.c[0], u.c[1], u.c[2], u.c[3]); } else { printf("%X.%X.%X.%X\n", u.c[3], u.c[2], u.c[1], u.c[0]); } exit(0); }
Пример 2
Код C:#define LITTLE_ENDIAN 0 #define BIG_ENDIAN 1 int endian() { int i = 1; char *p = (char *)&i; if (p[0] == 1) return LITTLE_ENDIAN; else return BIG_ENDIAN; }
Оставьте свой комментарий
Войдите, чтобы оставлять комментарии
Оставить комментарий как гость