Тестирование для Endianness: Почему работает следующий код?
В то время как я понимаю истинность, я немного не понимаю, как работает код ниже. Я предполагаю, что этот вопрос меньше о endianness и больше о том, как указатель char * и int работают, то есть преобразовывают тип. Кроме того, не имеет значения, если переменная word
не была short
, а просто int
? Спасибо!
#define BIG_ENDIAN 0
#define LITTLE_ENDIAN 1
int byteOrder() {
short int word = 0x0001;
char * byte = (char *) &word;
return (byte[0] ? LITTLE_ENDIAN : BIG_ENDIAN);
}
Ответы
Ответ 1
Короткий int состоит из двух байтов, в данном случае 0x00
и 0x01
. В маленькой системной системе первый байт приходит первым, поэтому в памяти он выглядит как 0x01
, за которым следует 0x00
. Естественно, что большие эндианные системы обращаются вспять. Вот как выглядят указатели для коротких целых чисел в маленькой системе:
----------------------- -----------------------
| 0x01 | 0x00 | | | |
----------------------- -----------------------
&word &word+1
Char указатели, с другой стороны, всегда увеличиваются последовательно. Таким образом, беря адрес первого байта целого числа и отбрасывая его на указатель char *
, вы можете увеличивать каждый байт целого числа по порядку памяти. Здесь соответствующая диаграмма:
------------ ------------ ------------ ------------
| 0x01 | | 0x00 | | | | |
------------ ------------ ------------ ------------
&byte &byte+1 &byte+2 &byte+3
Ответ 2
(char *)&word
указывает на первый (самый низкий адрес) char
(байт) word
. Если ваша система малозначна, это будет соответствовать 0x01
; если это big-endian, это будет соответствовать 0x00
.
И да, этот тест должен работать, будь то word
short
, int
или long
(если они больше по размеру, чем char
).
Ответ 3
Это милая маленькая программа. У вас есть слово, заданное шестнадцатеричным литералом 1. Если у вас мало конечного, младший байт (0x01 в этом случае) будет в байте [0], когда вы нарисуете указатель на указатель char. и поэтому, если 0x01 находится со смещением 0, то вы знаете, что это было немного endian, иначе, если 0x00 находится в смещении 0, вы знаете, что младший байт с синтаксисом был сохранен в более высокой ячейке памяти (смещение 1).
Примечание: указатели всегда указывают на самый низкий адрес памяти слова/структуры данных и т.д.
Ответ 4
Он сообщает вам о значении short
. По крайней мере, на некоторых машинах, где short
- ровно два байта. Это не обязательно говорит вам о контенте int
или long
, и, разумеется, когда интегральный тип больше двух байтов, выбор не является двоичным.
Реальный вопрос - вот почему вы хотели бы знать. Это почти всегда проще и надежнее писать код, так что это не имеет значения. (Есть исключения, но они почти всегда связаны с очень низким уровнем кода, который будет работать только на одном конкретном оборудовании. И если вы достаточно хорошо знаете аппаратное обеспечение, чтобы писать такой код, вы знаете его.)
Ответ 5
Трюк, который я использую, чтобы запомнить порядок байтов, когда мы думаем о big-endian vs little-endian, - "имена должны быть наоборот":
-
Когда вы пишете номер вручную, естественным способом сделать это является запись слева направо, начиная с самых значащих цифр и заканчивая наименее значимыми цифрами. В вашем примере вы должны сначала написать самый старший байт (то есть 0), то младший значащий байт (т.е. 1). Вот как работает великан. Когда он записывает данные в память (с увеличением адреса байта), он заканчивается наименее значимыми байтами - "маленькими" байтами. Итак, big-endian фактически заканчивается маленькими байтами.
-
То же самое для little-endian: на самом деле это заканчивается самым значительным байтом, то есть "большими" байтами.
Исходный код проверяет, является ли 1-й байт (то есть байтом [0]) самым значительным байтом (0), и в этом случае он является "старшим старшим" или небольшим порядком байтов.