Определите, является ли компилятор маленьким или большим endian в C

-6

Может ли кто-нибудь сказать мне, как эта программа может определить, является ли компилятор небольшим или большим.

#include <stdio.h>
#include <sys/types.h>
int main(void) {
union {
long lungo;
char ch[sizeof(long)];
} unione;
unione.lungo = 1;
if (unione.ch[sizeof(long)-1] == 0)
printf("little endian\n");
else
printf("big endian\n");
return (0);
}

Особенно я не понял, что делает эта часть программы:

union {
long lungo;
char ch[sizeof(long)];
} unione;

благодаря

спросил(а) 2021-01-19T14:03:07+03:00 6 месяцев, 1 неделя назад
1
Решение
78

union {
long lungo;
char ch[sizeof(long)];
} unione;

Это союз. Его члены занимают одну и ту же область памяти. Это общий трюк, чтобы написать одному члену (целое в этом случае)...

unione.lungo = 1;

... и затем читать обратно через другой (обычно это массив символов)...

if (unione.ch[sizeof(long)-1] == 0)

... чтобы получить байт-мудрый вид первого типа. (В этом случае "первый" байт целого числа, чтобы определить, появляется ли в нем 1 сохраненный в целочисленном (что делает это платформой с маленькими терминами), или нет (что сделало бы это big-endian платформе). Примечание @chux comment - существуют другие формы endianess, хотя они очень редки.

Приложение J.1 указывает "значение члена объединения, отличного от последнего, сохраненного в" как неопределенное.

В Приложении J.3.13 указано "количество, порядок и кодировка байтов в любом объекте (если это явно не указано в настоящем стандарте)", как определено в реализации.

В разделе 6.2.6 ("Представление типов") указано, что "определенные представления объектов не должны представлять значение типа объекта. Если хранимое значение объекта имеет такое представление и считывается выражением lvalue, которое не имеет символа тип, поведение не определено ".

Таким образом, хотя это не Undefined Behavior, эта конструкция... пусть скажем, приближается к боковой линии. ;-)

ответил(а) 2021-01-19T14:03:07+03:00 6 месяцев, 1 неделя назад
45

#define IS_BIG_ENDIAN (!*(unsigned char*)(void*)&(uint16_t){1}) - хороший способ сделать это, если ваш компилятор имеет uint16_t. Но вполне могут быть и другие схемы "суждения", которые могут дать вам ложный позитив. Я не уверен. В этот момент я бы приветствовал нижний план с контр-примером!

Технически поведение при использовании "профсоюзного трюка" не определено в C++, хотя вы сбежате с ним в C.

Литье через (void*) является излишним в C, но технически необходимо в C++.

ответил(а) 2021-01-19T14:03:07+03:00 6 месяцев, 1 неделя назад
45

Все члены союза занимают одну и ту же память, так что они накладываются друг на друга; письмо одному члену союза обновляет всех членов профсоюза.

Вы установили unione для хранения 2 участников; lungo является long, а ch представляет собой массив char размер которого равен размеру sizeof long байтов (4 или 8 байтов, в зависимости от вашей системы, для этого обсуждения мы примем 4 байта). Оба этих элемента накладываются друг на друга (они занимают одинаковые 4 байта памяти).

Помните, что в системе big- endian самый старший байт многобайтового типа будет сохранен по адресу A, а младший байт будет сохранен по адресу A + 3. В системе little-endian этот порядок отменяется; младший значащий байт будет сохранен по адресу A, а самый старший байт будет сохранен по адресу A + 3:

   BE:  A     A+1   A+2   A+3     where A is arbitrary address
---- ---- ---- ----
lungo: 0x00 0x00 0x00 0x01
---- ---- ---- ----
LE: A+3 A+2 A+1 A

С другой стороны, массивы всегда хранятся так, что a[0] хранится по адресу A, a[1] хранится в + 1 и т.д. Поэтому, если мы посмотрим на ch по отношению к lungo на обоих big- и мало-конечных систем, мы видим следующее:

   BE: ch[0]  ch[1]  ch[2]  ch[3]
----- ----- ----- -----
lungo: 0x00 0x00 0x00 0x01
----- ----- ----- -----
LE: ch[3] ch[2] ch[1] ch[0]

Таким образом, в системе little-endian ch[0] соответствует наименее lungo байту lungo, который содержит значение 0x01. В [end] системе big- ch[0] соответствует самому значащему байту lungo, который содержит значение 0x00.

Это общий трюк для определения сущности, но строго говоря, поведение не определено; вы не должны писать одному члену союза и читать от другого члена. Этот метод "работает", потому что любой многобайтовый тип может быть корректно отображен на массив char или unsigned char, но это не то, что может быть чисто применено между двумя многобайтовыми типами в целом.

Нет 100% портативного, стандартного способа определения сущности системы, по крайней мере, того, о чем я знаю. Все, что я знаю, включают в себя такие трюки, как это или какой-то тип, карающий, например

long l = 0x00010203;
char *c = (char *) &l;
if ( c[0] == 0x03 )
// little-endian
else if ( c[0] == 0x00 )
// big-endian
else
// something else

Опять же, это не хорошая практика и, вероятно, не определена, но она "работает" для большинства случаев.

big- и малозначивость - это не единственные возможные порядки, и в одной системе возможно несколько заказов. VAXen обычно были малоподобными, за исключением 32-битных поплавков, которые были "средними" и выложены как 2301.

ответил(а) 2021-01-19T14:03:07+03:00 6 месяцев, 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема