我刚刚处理了一个有趣的问题,但我看不出有什么巧妙的方法来解决它。
我有两个表示复杂图形的基本数据结构,声明如下:
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
当然,这会导致一些问题,因为“偏移”值变得不正确,但这并不那么明显,因为数据结构的所有其他使用都有效(没有“真正的”对齐问题)。
这归结为我的问题 - 当偏移量不能表示为元素的整数时,您是否看到增加指针的一种巧妙方法?
找到一种不诉诸过度施法的方法的奖励积分:)