Я считаю, что нашел способ добиться чего-то вроде известного "хачка-структуры" в портативном 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?