Это расположение памяти и информирование компилятора. Компилятор может выбрать размещение структуры по выровненному адресу, но это не обязательно будет делать, если структура заменяется всеми содержащимися в ней элементами. Может быть разница в байтах заполнения.

я есть структура X, которая наследует от структуры Base. Тем не менее, в моей текущей настройке, из-за выравнивания, размер X равен 24B:

typedef struct {
    double_t a;
    int8_t b;
} Base;

typedef struct {
    Base base;
    int8_t c;
} X;

Чтобы сохранить память, я хотел бы развернуть структуру Base, поэтому я создал структуру Y, которая содержит поля из Base (в том же порядке, всегда в начале структуры), поэтому размер структуры составляет 16B :

typedef struct {
    double_t base_a;
    int8_t base_b;
    int8_t c;
} Y;

Затем я собираюсь использовать экземпляр структуры Y в методе, который ожидает указатель на структуру Base:

void print_base(Base* b)
{
  printf("%f %d\n", b->a, b->b);
}
// ...
Y data;
print_base((Base*)&data);

Нарушает ли приведенный выше код строгое правило псевдонимов и вызывает неопределенное поведение?

Ответы на вопрос(1)

Ваш ответ на вопрос