将结构指针转换为另一个嵌入结构

标签 c pointers struct stack

我正在实现一个不需要内存分配的堆栈,并且可以采用任何结构,只要它嵌入特殊结构即可。类似于 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/

相关文章:

c - 链表指针类型错误?

c - 在 gdb 调试器中找不到调试符号

c - 如何将结构体数组传递给函数

C指针和数组问题

c - 如何传递指针并在堆上分配空间

c++ - 是否有一种技术可以让匿名结构的命名实例引用封闭类中的函数?

c - 错误 : field has incomplete type

c - C 中变量和数组中的指针取消引用

c - 这段 C 代码的作用是什么? [与函数体代码混淆]

c++ - 结构成员地址之间的差异作为编译时间常数