我正在实现一个不需要内存分配的堆栈,并且可以采用任何结构,只要它嵌入特殊结构即可。类似于 GNU's List实现。
任何结构必须嵌入才能在堆栈中工作的结构是:
struct stack_elem {
struct stack_elem *next;
};
我希望与堆栈一起使用的结构是:
struct node {
double number;
char character;
int isNumber;
struct stack_elem elem;
};
所以堆栈看起来像这样:
node: node:
+---------+ +---------+
|number | |number |
+---------+ +---------+
|character| |character|
+---------+ +---------+
|isNumber | |isNumber |
+---------+ +---------+
|elem | |elem |
| *next |----->| *next |
+---------+ +---------+ etc....
我正在编写一个名为 stack_entry
的宏,以将嵌入的 elem
结构转换为其容器 node
结构。这是我到目前为止所尝试过的。 stack_entry
将按如下方式使用:
struct stack_elem *top = peek(&stack);
struct node *converted_node = stack_entry(top, struct node, elem);
stack_entry
将获取一个指向 stack_elem
的指针、要转换到的节点的类型以及该节点中元素的成员字段的名称。我尝试了多种方法来做到这一点,但没有任何效果。我意识到 STACK_ELEM
指向 next
项,因此我尝试从 struct node
中减去 elem
的偏移量但这没有用。以下是我尝试过的一些方法,但也不起作用:
#define stack_entry(STACK_ELEM, STRUCT, MEMBER) \
((STRUCT *) &(STACK_ELEM) - offsetof (STRUCT, MEMBER))
#define stack_entry(STACK_ELEM, STRUCT, MEMBER) \
((STRUCT *) ((uint8_t *) &(STACK_ELEM)->next \
- offsetof (STRUCT, MEMBER)))
正确的算术是什么?为什么不减去 next
的偏移量,从而减去 elem
的偏移量,如果它是结构中的最后一个元素,则生成节点?
GNU List list_entry
宏定义为:
#define list_entry(LIST_ELEM, STRUCT, MEMBER) \
((STRUCT *) ((uint8_t *) &(LIST_ELEM)->next \
- offsetof (STRUCT, MEMBER.next)))
这是如何工作的?当 next
应该获取同一节点内的容器结构而不是 next
时,为什么这里会涉及到 next
呢?
最佳答案
GNU 的 list_entry
的工作原理是从 next
字段的地址中减去从结构体开头到 next
字段的偏移量。它实际上并没有取消引用 next
指针。 Linux 源代码中有一个用于此目的的通用宏,名为container_of
。 ,您可能会发现这很有帮助。链接的文章内容非常丰富。
在第二次尝试定义 stack_entry
时,您减去了错误的偏移量(将其与 GNU list_entry
宏进行比较)。
关于将结构指针转换为另一个嵌入结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11419833/