1

次の形式の構造体があります。

typedef struct node {
  unsigned int * keys;
  unsigned int * branches;
} NODE;

キーとブランチの数は実行時に決定されますが、既知です。これは別の構造体から派生しています。

typedef struct tree {
  unsigned int num_keys_per_node;
} TREE;

NODEこのに を割り当てるにはTREE、手動の手順は次のようになります。

NODE node;
unsigned int keys[tree->num_keys_per_node];
unsigned int branches[tree->num_keys_per_node + 1];

node.keys     = keys;
node.branches = branches;

これらのノードの多くをタイトなループ内に割り当てる必要がありますが、データ構造をトラバースするときに一時的にのみ使用し、ノードのトラバーサルが続くとすぐにそれらを破棄します。malloc()ポインター、キー、ヒープ上の分岐を返す関数をfree()手動で作成することもできますが、可能であればスタックを使用することをお勧めします。

この初期化ロジックは多くの場所で繰り返されるため、マクロを定義して、次のようなことを効果的に行うにはどうすればよいですか。

NODE node = CREATE_NODE_FOR_TREE(tree);

プリプロセッサが有効な構文を提供する結果となるこれを行う方法を見つけるのが難しいです。

スタック メモリでの動的な構造体の割り当てに対する他のアプローチも聞けてうれしいです。

編集 | メモリ内に同時に複数のノードが必要になることはないため、1 つの構造体を繰り返し再利用することもできます。

4

3 に答える 3

1

node次のように引数としてマクロに渡してみてください。

#define CREATE_NODE_FOR_TREE( \
  node, \
  tree) \
  \
  unsigned int keys[tree->num_keys_per_node]; \
  unsigned int branches[tree->num_keys_per_node + 1]; \
  \
  node.keys     = keys; \
  node.branches = branches; 

...
NODE node = {0};
CREATE_NODE_FOR_TREE(node, tree);
...

このソリューションは、少なくとも c99 を想定しています。

于 2012-04-15T07:58:21.767 に答える
1

複合リテラルは VLA にすることはできず、サイズ パラメーターは動的であるため、提案する構文で直接行うことはできません。私は次のことをします:

#define NODE_ON_STACK(NAME, TREE)                         \
NODE NAME = { 0 };                                        \
register size_t NAME ## keys = (TREE)->num_keys_per_node; \
auto unsigned int NAME ## keys[NAME ## keys];             \
auto unsigned int NAME ## branches[NAME ## keys + 1];     \
node.keys     = NAME ## keys;                             \
node.branches = NAME ## branches

これは、複数の宣言を配置できる関数スコープ内の任意の場所で機能します。registerファイルスコープで使用されautoないようにしてください。このNAME ## keys変数により、TREE引数が 1 回だけ評価されることが保証されます。必要に応じて、競合を避けるために、生成された識別子の名前をもう少しマングルすることもできます。

要点:

  • 常にstruct変数を初期化する
  • あなたのTREEことは質問でどういうわけか間違っていました
  • あなたの質問の&演算子は間違っていました
  • int整数型はほぼ確実に間違っているため、ものを数えているものはunsigned
  • unsigned intも間違っていsize_tます。通常、オブジェクトまたはその一部をカウントすることになっているすべてのものに最適です。

ああ、通常の警告タグ:auto変数としての VLA は、stackoverflow のために慎重に使用する必要があります。しかし、あなたはすでにそれを知っていたと思います。

于 2012-04-15T08:17:33.410 に答える
0

次のようなことがうまくいくと思いますが、これが最善の方法であるかどうかはわかりません。

#define PASTE2(x,y) x##y
#define PASTE(x,y)  PASTE2(x,y)

#define CREATE_NODE_FOR_TREE( n, tree) \
    NODE n;                         \
    unsigned int PASTE(n,_keys)[(tree)->num_keys_per_node];         \
    unsigned int PASTE(n,_branches)[(tree)->num_keys_per_node + 1]; \
    n.keys     = &PASTE(n,_keys);                                \
    n.branches = &PASTE(n,_branches);

トークンの貼り付けは、ある時点で一度に複数を使用する必要がある場合にNODE、「非表示」keysおよびbranchesローカルの名前を名前に「スコープ」してNODE、競合を回避できるようにするためのものです。それを使用するには、代わりに

NODE node = CREATE_NODE_FOR_TREE(tree);

node次のように宣言して初期化します。

CREATE_NODE_FOR_TREE(node, tree);
于 2012-04-15T07:57:27.717 に答える