我有一个结构形式:
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);
我很难看到这样做的方法,这会导致预处理器提供有效的语法。
很高兴听到堆栈内存上动态结构分配的其他方法。
编辑|我不应该同时在内存中需要多个节点,所以我也可以重复使用一个结构。
答案 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
这适用于功能范围内可以放置多个声明的任何位置。 register
和auto
确保它永远不会在文件范围中使用。 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
,则“隐藏的”keys
和branches
本地人会有他们的名字'scoped'到NODE
名称以避免冲突。
要使用它,而不是
NODE node = CREATE_NODE_FOR_TREE(tree);
你会像这样声明并初始化node
:
CREATE_NODE_FOR_TREE(node, tree);