Будет ли выравнивание переменных в C-соединении одинаковым для всех систем?

Рассмотрим следующий союз:

typedef union {
    struct { // Anonymous struct
        int red;
        int green;
        int blue;
    };
    int colorChannels[3];
} Color;

Независимо от системы, этот код компилируется или выполняется, будут ли поля в анонимной структуре всегда совпадать с индексами в colorChannels?

Другими словами, спецификация требует, чтобы адрес памяти myColor.colorChannels[0] был таким же, как адрес myColor.red?

Кроме того, будет ли отличаться ответ, если код был скомпилирован как С++, а не C?

Обратите внимание, что я спрашиваю о конкретном случае, когда каждый элемент в объединении имеет тот же тип/размер (т.е. int в этом случае)

Ответ 1

Независимо от системы, этот код компилируется или выполняется, будут ли поля в анонимной структуре всегда совпадать с индексами в colorChannels?

Не обязательно. Реализация может добавлять байты "отступы" между отдельными переменными struct. "Заполнение" - это всего лишь дополнительные байты памяти, вставленные в определение памяти между переменными или в конце struct в соответствии с реализацией. Если это произошло, то ваш целочисленный массив не будет совмещен с макетом памяти struct (если, например, дополнение не было только в конце struct). Порядок переменных в struct в памяти должен быть согласованным во всех реализациях (в этой переменной a будет следовать b, за которым следует c в памяти), но, опять же, заполнение байтов между ними может быть там (например, за a следует b в памяти, но есть отступы между a и b, так что они не сразу после друг друга в памяти).

Для некоторых компиляторов, таких как gcc, есть способы изменить, как он обрабатывает дополнение. Это может помочь гарантировать, что struct будет в выравнивании памяти с вашим целым массивом, но это может вызвать проблемы с памятью ниже по течению.

Другими словами, спецификация требует, чтобы адрес памяти myColor.colorChannels [0] был таким же, как адрес myColor.red?

Если между red, green и blue от struct нет отступов, то индексы colorChannels будут соответствовать каждой переменной в памяти.

Ответ 2

Стандарт C не дает никаких гарантий об этом, но он, вероятно, будет правильным для любой существующей существующей системы.

Я бы предложил добавить в код проверку времени компиляции, чтобы в случае, если есть какая-то система, которая добавляет дополнение, вы получаете ошибку компиляции, с которой вы можете иметь дело в то время:

_Static_assert( sizeof(Color) == 3 * sizeof(int),  "We're on a weird system boys." );

NB. _Static_assert был добавлен в C11, до этого вы можете использовать некоторые хаки как описано здесь