対処すべき興味深い問題が発生しましたが、それをうまく解決する方法がわかりません。
複雑なグラフを表す 2 つの基本データ構造があり、次のように宣言されています。
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
もちろん、「オフセット」値が正しくなくなるため、少し問題が発生しますが、データ構造の他のすべての使用が機能するため、それほど明白ではありません (「実際の」アライメントの問題はありません)。
私の質問に要約すると、オフセットを要素の整数として表現できない場合に、ポインターをインクリメントするきちんとした方法がわかりますか?
過度のキャストに頼らない方法を見つけるためのボーナスポイント:)