Тестирование для 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), и в этом случае он является "старшим старшим" или небольшим порядком байтов.