我正在实现一个不需要内存分配的堆栈,只要它嵌入一个特殊的结构就可以使用任何结构。与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
项,因此我尝试从elem
中减去struct node
的偏移量,但这不起作用。以下是我尝试过的一些不起作用的事情:
#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_entry
宏定义为:
#define list_entry(LIST_ELEM, STRUCT, MEMBER) \
((STRUCT *) ((uint8_t *) &(LIST_ELEM)->next \
- offsetof (STRUCT, MEMBER.next)))
这是如何工作的?为什么next
在它应该在同一个节点内而不是next
中抓取容器结构时参与其中?
答案 0 :(得分:3)
GNU的list_entry
通过从next
字段的地址减去从结构开头到next
字段的偏移量来工作。它实际上并没有取消引用next
指针。在名为container_of
的Linux源代码中有一个常用的宏,您可能会发现它很有帮助。链接的文章非常有用。
在第二次尝试定义stack_entry
时,减去错误的偏移量(将其与GNU list_entry
宏进行比较)。
答案 1 :(得分:1)
您的实现实际上不是堆栈,而是单个链接列表或向量,具体取决于您的数据结构是否具有任意大小。
仅供您考虑:
如果您的元素大小相同,为什么还需要下一个指针。它们不应该相互抵消吗? 假设您的结构大小为16个字节。第一个元素位于地址 base ,下一个元素位于地址 base + 16 , n -th元素位于 base +(n-1) * 16 (然后你称之为向量)
如果您的数据结构具有任意大小,则需要两件事:找出它是哪个对象以及固定偏移到下一个指针的位置。两个好的提示:
对您来说最好的事情是:它已由其他人实施:您可以使用#include <sys/queue.h>
SLIST
,然后您只需要处理数据的放置位置。