Соответствующий вариант старого "структурного взлома" (?)

Я считаю, что нашел способ добиться чего-то вроде известного "хачка-структуры" в портативном C89. Мне любопытно, если это действительно строго соответствует C89.

Основная идея: я выделяю достаточно большую память, чтобы содержать начальную структуру и элементы массива. Точный размер (K + N) * sizeof(array_base_type), где K выбирается так, чтобы K * sizeof(array_base_type) >= sizeof(the_struct) и N было числом элементов массива.

Сначала я разыграю указатель, который malloc() вернулся для хранения the_struct, затем я использую арифметику указателя, чтобы получить указатель на начало массива, следующего за структурой.

Одна строка кода стоит более тысячи слов, поэтому вот минимальная реализация:

typedef struct Header {
    size_t length;
    /* other members follow */
} Header;

typedef struct Value {
    int type;
    union {
        int intval;
        double fltval;
    } v;
} Value;

/* round up to nearest multiple of sizeof(Value) so that a Header struct fits in */
size_t n_hdr = (sizeof(Header) + sizeof(Value) - 1) / sizeof(Value);

size_t n_arr = 42; /* arbitrary array size here */
void *frame = malloc((n_hdr + n_arr) * sizeof(Value));

if (!frame)
    return NULL;

Header *hdr = frame;
Value *stack_bottom = (Value *)frame + n_hdr;

Моя основная проблема заключается в том, что последние два назначения (используя frame как указатель на заголовок и указатель на значение) могут нарушать правило строгого сглаживания. Однако я не пересматриваю hdr как указатель на Value - это только арифметика указателя, которая выполняется на frame, чтобы получить доступ к первому элементу массива значений, поэтому я не могу эффективно обращаться к одному и тому же объекту, используя указатели разных типов.

Итак, этот подход лучше, чем классический хакер (который официально считается UB), или он тоже UB?

Ответ 1

"Очевидное" (ну... не совсем очевидно, но это то, что приходит мне на ум: -)), чтобы заставить это сломаться, - использовать компилятор векторизации, который каким-то образом решает его нормально загружать, скажем, 64 Header в векторный регистр из 42-округленной вверх-64 + области в hdr, которая исходит от malloc, которая всегда выделяет достаточно для векторизации. Сохранение векторного регистра обратно в память может перезаписать один из Value s.

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

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