1

我有一个形式的结构:

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

键和分支的数量是在运行时确定的,但是是已知的。它派生自另一个结构:

typedef struct tree {
  unsigned int num_keys_per_node;
} TREE;

为了为此分配 a NODETREE手动步骤将是:

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);

我很难找到一种方法来做到这一点,这将导致预处理器给出有效的语法。

很高兴听到其他在堆栈内存上进行动态结构分配的方法。

编辑 | 我不应该同时在内存中需要多个节点,所以我也可以重复使用一个结构。

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 并且您的 size 参数是动态的,因此不可能直接使用您建议的语法来执行此操作。我会做以下事情:

#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

这适用于函数范围内可以放置多个声明的任何位置。registerauto确保它永远不会在文件范围内使用。该NAME ## keys变量确保TREE参数只被评估一次。如果您愿意,您还可以修改生成的标识符的名称以避免冲突。

挑剔:

  • 总是初始化struct变量
  • TREE的问题在问题上有些错误
  • 您问题中的&操作员错了
  • int由于整数类型几乎肯定是错误的,所以计数的东西应该是unsigned
  • unsigned int也是错误的,size_t通常最适合应该计算对象或其部分的所有内容。

啊和通常的警告标签:auto由于stackoverflow,VLA作为变量要小心。但我想你已经知道了。

于 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,“隐藏”keysbranches本地人的名称将“限定”到NODE名称以避免冲突。使用它,而不是

NODE node = CREATE_NODE_FOR_TREE(tree);

你会node像这样声明和初始化:

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