Союзный взлом для тестирования и байта байтов

Для объединения запись в один элемент и чтение из другого члена (кроме массива 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, оставаясь полностью в рамках правил!