Соответствующий вариант старого "структурного взлома" (?)
Я считаю, что нашел способ добиться чего-то вроде известного "хачка-структуры" в портативном 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.
Я думаю, что этот векторный компилятор может указывать на стандарт (ну, если у компилятора есть пальцы...) и требовать соответствия.
На практике, однако, я ожидаю, что этот код будет работать. Если вы сталкиваетесь с векторизованным компилятором, добавьте еще больше места (сделайте округление с помощью макроса, зависящего от машины, который может вставить минимум) и зарядите.: -)