Linux内核代码中的C宏扩展

时间:2010-04-20 08:44:50

标签: c linux list macros c-preprocessor

我在写 C 时通常忽略了使用宏,但我想我知道它们的基本原理。当我在linux内核中阅读list的源代码时,我看到了类似的东西:

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
    struct list_head name = LIST_HEAD_INIT(name)

(您可以从here.

访问代码的剩余部分

我在LIST_HEAD_INIT中并不理解&符号的功能(我不认为它们是操作数的地址),因此在代码中使用了LIST_HEAD_INIT。如果有人能够启发我,我会很感激。

5 个答案:

答案 0 :(得分:15)

要知道实际发生了什么,我们需要定义struct list_head

struct list_head {
        struct list_head *next, *prev;
};

现在考虑一下宏:

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)

如果在代码中我写LIST_HEAD(foo),它会扩展为:

struct list_head foo = { &(foo) , &(foo)}

表示带有标头节点的空双向链表,其中nextprev指针指向标头节点本身。

与做:

相同
struct list_head foo;
foo.next = &foo;
foo.prev = &foo;

因此,这些宏有效地提供了一种初始化双向链表的方法。

是的,这里使用&作为运营商的地址。

修改

这是working example

在您提供的链接中。你有:

struct list_head test = LIST_HEAD (check);

这是不正确的。你应该:

LIST_HEAD (check);

答案 1 :(得分:8)

每次你对宏实际上在做什么都有疑问时,你可以让'gcc -E'为你扩展它。

在这种情况下,它只是初始化一个包含指向自身的列表结构。

答案 2 :(得分:3)

他们是这里的运营商地址。内核中的链表避免使用空指针来表示列表的结尾。因此,必须使用一些有效指针初始化标头。在此实现中,如果“head”或“tail”指针指向列表标题的地址,则该列表被视为空。

答案 3 :(得分:1)

宏本身似乎没有在list.h中使用。

我认为&的确代表了代码中的地址。 struct list_head包含两个指针,因此声明struct list_head name = LIST_HEAD_INIT(name)(请参阅宏LIST_HEAD)获取一对指针作为初始化器应该是很自然的。

答案 4 :(得分:0)

这正是它们的原因,&符号取参数的地址并将它们存储在“head”和“next”列表字段中。无法告诉你为什么,因为我没有找到这个宏的实际用途,但这就是它的作用。