Союзный взлом для тестирования и байта байтов
Для объединения запись в один элемент и чтение из другого члена (кроме массива char) - это UB.
//snippet 1(testing for endianess):
union
{
int i;
char c[sizeof(int)];
} x;
x.i = 1; // writing to i
if(x.c[0] == 1) // reading from c[0]
{ printf("little-endian\n");
}
else
{ printf("big-endian\n");
}
//snippet 2(swap bytes using union):
int swapbytes()
{
union // assuming 32bit, sizeof(int)==4
{
int i;
char c[sizeof(int)];
} x;
x.i = 0x12345678; // writing to member i
SWAP(x.ch[0],x.ch[3]); // writing to char array elements
SWAP(x.ch[1],x.ch[2]); // writing to char array elements
return x.i; // reading from x.i
}
Фрагмент 1 - это законный C или С++, но не фрагмент 2. Правильно ли я? Может ли кто-нибудь указать на раздел стандарта, где он говорит, что его ОК, чтобы написать члену союза и прочитать от другого члена, который является массивом char.
Ответы
Ответ 1
Я считаю, что это (фрагмент 1) технически не разрешен, но большинство компиляторов разрешают его в любом случае, потому что люди используют этот тип кода. GCC даже документы, которые поддерживаются.
У вас есть проблемы на некоторых машинах, где sizeof (int) == 1 и, возможно, на некоторых, которые не являются ни большими, ни маленькими endian.
Используйте либо доступные функции, которые меняют слова в правильном порядке, либо задают это с помощью макроса конфигурации. Вероятно, вам все равно нужно распознавать компилятор и ОС.
Ответ 2
Существует очень простой способ, который обходит поведение undefined (ну неопределенное поведение, которое определяется почти в каждом компиляторе там;)).
uint32_t i = 0x12345678;
char ch[4];
memcpy( ch, &i, 4 );
bool bLittleEndian = ch[0] == 0x78;
У этого добавочного бонуса, что почти каждый компилятор там увидит, что вы memcpying постоянное количество байтов и полностью оптимизируйте memcpy, в результате чего точно такой же код, что и ваш фрагмент 1, оставаясь полностью в рамках правил!