Справочная информация : у меня есть подпрограмма C99, для которой требуется временное хранение различных типов данных с различными требованиями к выравниванию. В настоящее время я звоню posix_memalign
несколько раз, что а) приводит к большим накладным расходам и б) не гарантирует, что мои временные архивы имеют хорошую память. Я не могу упаковать временные файлы в одну структуру, так как требования к размеру известны только во время выполнения.
Вопрос : Я хочу позвонить malloc
(или что-то подобное) один раз с достаточно большим размером, чтобы я мог нарезать / разделять / разбивать отдельные указатели с требуемым выравниванием. Есть ли канонический способ выполнить эту задачу в C99?
Возможный (но маловероятный) ответ для конкретного примера : скажем, я хочу выделить достаточно места для char[3]
, double[m]
с 16-байтовым выравниванием, int
и float[n]
с 16-байтовым выравниванием и что мне нужно их в памяти в таком порядке. Пожалуйста, не обращайте внимания на то, что заказ глуп и пример придуман. Мой фактический вариант использования - это управляющая структура, за которой следуют несколько временных массивов смешанных целочисленных / числовых типов с выравниваниями, позволяющими выполнять операции SSE.
Используя идеи Как распределить выровненную память только с использованием стандартной библиотеки? можно сделать:
// Several unnecessary values (e.g. alignment_c) are holdovers
// from the macros generating this logic.
// ell, m, and n are sizes known only at runtime
const size_t datasize_c = 3*sizeof(char);
const size_t alignment_c = __alignof__(char);
const size_t pad_c = alignment_c - 1;
const uintptr_t mask_c = ~(uintptr_t)(alignment_c - 1);
const size_t datasize_d = ell*sizeof(double);
const size_t alignment_d = __alignof__(double) > 16 ? __alignof__(double) : 16;
const size_t pad_d = alignment_d - 1;
const uintptr_t mask_d = ~(uintptr_t)(alignment_d - 1);
const size_t datasize_i = m*sizeof(int);
const size_t alignment_i = __alignof__(int);
const size_t pad_i = alignment_i - 1;
const uintptr_t mask_i = ~(uintptr_t)(alignment_i - 1);
const size_t datasize_f = n*sizeof(float);
const size_t alignment_f = __alignof__(float) > 16 ? __alignof__(float) : 16;
const size_t pad_f = alignment_f - 1;
const uintptr_t mask_f = ~(uintptr_t)(alignment_f - 1);
const size_t p_parcel = (datasize_c + pad_c)
+ (datasize_d + pad_d)
+ (datasize_i + pad_i)
+ (datasize_f + pad_f) ;
void * const p = malloc(p_parcel) ;
char * c = (void *) (((uintptr_t)(p ) + pad_c & mask_c));
double * d = (void *) (((uintptr_t)(c + ell) + pad_d & mask_d));
int * i = (void *) (((uintptr_t)(d + m ) + pad_i & mask_i));
float * f = (void *) (((uintptr_t)(i + n ) + pad_f & mask_f));
// check if p is NULL, use (c, d, i, f), then free p
Я считаю, что эта возможность функционально верна, но мне интересно, есть ли у кого-нибудь лучший, чище, короткий путь?
Я думаю, что подходы, использующие struct hack, неосуществимы, потому что я могу гарантировать выравнивание только одного массива, используя malloc одного взлома struct. Мне все еще нужно три malloc
вызова для трех отдельных структурных хаков.
Наконец, я был бы рад предоставить макросы, которые генерируют этот беспорядок, если кто-то хочет их.