У меня просто возникла интересная проблема, о которой я забочусь, и я не вижу аккуратного способа ее решения.Увеличьте указатель структуры с половиной размера структуры
У меня есть две структуры базы данных, которая представляет собой сложный график, заявил что-то вроде этого:
typedef struct _node_t node_t;
typedef struct _graph_t graph_t;
struct {
/* Data fields omitted */
node_t * pNextByLevel;
node_t * pNextByProximity;
node_t * pNextByRank;
} node_t;
struct {
/* Data fields omitted */
size_t nNodes;
size_t nMaxNodes;
node_t * pFirstByLevel;
node_t * pFirstByProximity;
node_t * pFirstByRank;
} graph_t;
Фактические узлы раскладывают сразу после заголовка, так «graph_t» обычно создается с
graph_t * pNewBuffer = calloc(1, sizeof(graph_t) + nMaxNodes * sizeof(node_t));
pNewBuffer->nMaxNodes = nMaxNodes;
и "сырой" массив узлов доступа с
node_t * pNewBufferNodes = (node_t *) &pNewBuffer[1];
Теперь существует функция поддержки, которая работает с буфером, который уменьшает количество узлов. Это выглядит примерно так:
status_t reduce(graph_t** ppBuffer)
{
graph_t * pReplacement, * pOld = *ppBuffer;
size_t nRequired;
node_t * oldBuffer = (node_t *) &pOld[1];
/* complex calculation ultimately computes 'nRequired' */
pReplacement = realloc(pOld, sizeof(graph_t) + nRequired * sizeof(node_t));
if (pReplacement != pOld)
{
int i;
node_t * newBuffer = (node_t *) &pReplacement[1];
ptrdiff_t offset = newBuffer - oldBuffer;
for (i = 0; i < requiredNodes; i++)
{
newBuffer[i].pFirstByLevel += offset;
newBuffer[i].pFirstBySimilarity += offset;
newBuffer[i].pFirstByRank += offset;
}
*ppBuffer = pReplacement;
}
}
Теперь это прекрасно работает в течение длительного времени. Любые ошибки в вышесказанном возникают из-за того, что я пишу из памяти, я просто пытаюсь объяснить эту идею.
Что меня сейчас озаряет, так это то, что при использовании функции сокращения от нового модуля вход не выравнивается «правильно». Когда я анализирую адреса, отмечу следующие свойства:
((char *) newBuffer - (char *) oldBuffer) % sizeof(graph_t) == 0
((size_t) newBuffer) % sizeof(node_t) == 0
((size_t) oldBuffer) % sizeof(node_t) == 0
((char *) newBuffer - (char *) oldBuffer) % sizeof(node_t) == sizeof(node_t)/2
, который, конечно же, вызывает немного проблемы, так как «смещение» значение становится неправильным, но это не так очевидно, так как все другое использование данных (нет «реальной» проблемы выравнивания).
Это сводится к моему вопросу. Вы видите аккуратный способ увеличения указателей, когда смещение не может быть выражено как целое число элементов?
Бонусные баллы для нахождения пути, не прибегать к чрезмерному отливке :)
Я озадачен тем, что происходит с как oldBuffer, так и newBuffer, кратным 'sizeof (node_t)' при приведении к 'size_t', и тем не менее их различие не является кратным. В общем случае нет причин, по которым адрес буфера * должен быть * кратным «sizeof (node_t)» - обычно требование выравнивания для структуры является наибольшим требованием выравнивания для любого члена, а не для общего размера. –
Тот факт, что «это прекрасно работало в течение длительного времени», было просто удачей. Как сказал один из них, нет причин, по которым адреса двух буферов должны быть кратными size_t (node_t), он должен быть только кратным требованию выравнивания. Также обратите внимание, что способ выделения вещей не гарантируется для вашего массива node_t, если требование выравнивания для graph_t не будет таким же или строже, чем требование для node_t. –
Незначительная коррекция на то, что я сказал: для распределения указано, что она выровнена с наибольшим требованием выравнивания любого типа, меньшего размера структуры, и на самом деле он не должен быть членом. Я говорю «указано», а не «гарантировано», потому что в последний раз я слышал, что ядро Linux было спором с gcc, над чьей ответственностью это делается на самом деле. Но если sizeof (node_t) равно 16, совершенно неправдоподобно, чтобы все достаточно большие распределения были выровнены по 16 на определенной платформе. Вероятно, из-за того, как работает распределитель, а не потому, что есть 16-байтовый тип, ofc. –