使用预先计算的成员长度在堆栈上分配struct的宏

时间:2012-04-15 07:35:58

标签: c macros struct

我有一个结构形式:

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

我很难看到这样做的方法,这会导致预处理器提供有效的语法。

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

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

3 个答案:

答案 0 :(得分: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。

答案 1 :(得分: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通常最适合所有事情 应该计算对象或部分对象。

啊和通常的警告标签:因为stackoverflow,要小心谨慎地采用VLA作为auto变量。但我想,你已经知道了。

答案 2 :(得分: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本地人会有他们的名字'scoped'到NODE名称以避免冲突。 要使用它,而不是

NODE node = CREATE_NODE_FOR_TREE(tree);

你会像这样声明并初始化node

CREATE_NODE_FOR_TREE(node, tree);