【问题标题】:c programming #define struct { } declaringc编程#define struct {}声明
【发布时间】:2017-02-01 15:26:43
【问题描述】:

我在看 Glibc 代码。 glibc 队列的一些代码引起了我的注意。我无法为这个结构定义赋予意义。这个结构没有名字。为什么?它是如何工作的?

#define LIST_ENTRY(type)                        \
struct {                                \
    struct type *le_next;   /* next element */          \
    struct type **le_prev;  /* address of previous next element */  \
}

Source

【问题讨论】:

  • 看起来像是模板的替代品。
  • 在许多情况下,宏表示部分代码。看看这个宏是如何在后面的代码中使用来查看完整的构造的。在那里,我敢肯定,您会看到缺少的名称以及所有必要的信息。
  • 请注意,您引用的标题会将人们定向到 the manual page for queue(3) 以获取使用文档。你读过那页吗?它确实为该宏和该文件中的其他宏提供了解释、使用说明和示例代码。

标签: c glibc


【解决方案1】:

这实际上是一个预处理器宏,可以在其他地方扩展(很可能带有尾随名称)。

在该头文件开头的 cmets 中有对 queue(3) man page 的引用,其中包含有关该宏和其他宏的更多详细信息:

宏 LIST_ENTRY 声明了一个连接元素的结构 在列表中。

还有一个使用示例:

LIST_HEAD(listhead, entry) head = LIST_HEAD_INITIALIZER(head);  
struct listhead *headp;                 /* List head. */
struct entry {  
  ...  
  LIST_ENTRY(entry) entries;      /* List. */  
  ...  
}  
*n1, *n2, *n3, *np, *np_temp;  

LIST_INIT(&head);                       /* Initialize the list. */  

n1 = malloc(sizeof(struct entry));      /* Insert at the head. */   
LIST_INSERT_HEAD(&head, n1, entries);

作为这个 C 代码(不是 C++),并且 C 缺少模板,这个预处理器宏可以用来“模拟”模板(注意 type 参数)。

【讨论】:

  • 感谢 cmets,经过编辑以提供更好、更完整的使用示例。
  • @LightnessRacesinOrbit 我的评论在问题被编辑后不再有意义,所以我删除了它。
  • @epoxy 如果对您有帮助,请点击它附近的勾号接受答案
【解决方案2】:

这是一个用于声明结构类型的宏,nextprev 指向第二个结构类型的实例。第二种类型可以是父类型,因此您可以像这样创建“可链接结构”:

struct foo {
  LIST_ENTRY(foo) list;
  int value;
};

这会创建一个struct foo,其中包含一个名为list 的成员,该成员又是问题中的结构,其指针指向struct foo

我们现在可以像这样创建一个struct foos 的小链表:

struct foo fa, fb;
fa.value = 47;
fa.list.le_next = &fb;
fa.list.le_prev = NULL;
fb.value = 11;
fb.list.le_next = NULL;
fb.list.le_prev = &fa.list.le_next;

我不是 100% 确定最后一行,但我认为这有点道理。

【讨论】:

  • 由于您将标识符list 提供给struct foo 中的列表成员,因此您需要使用fa.list.le_next 而不是fa.le_nextle_prev 也是如此)。但是,您可以通过将列表成员声明为LIST_ENTRY(foo); 来使其匿名,然后您可以访问fa.le_nextfa.le_prev
  • @IanAbbott 谢谢!当然是固定的。还有天啊,不是匿名会员C11吗? :)
  • 请注意 sys/quque.h 还带有宏来添加/删除/等。从这样的列表中(记录在man7.org/linux/man-pages/man3/queue.3.html
  • 我认为匿名结构成员变体是比命名结构变体更可能的使用模型。当然,宏可以同时支持两者。
  • 我猜非匿名版本会更便携,但是一些 C11 之前的编译器也支持匿名成员。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-28
相关资源
最近更新 更多