Linux中的list_entry

时间:2011-04-05 10:26:11

标签: c linux linux-kernel

user/include/linux/list.h

这个声明:

#define list_entry(ptr, type, member) \
((type *)((char *)(ptr) – (unsigned long)(&((type *)0)->member)))

有人可以解释这是什么以及如何运作,提前谢谢

P.S。请尽可能地简化你的答案,我知道Linux中的线程,进程,现在我正在探索可能性,而且我对这个有点困惑。

3 个答案:

答案 0 :(得分:29)

考虑两个这样的结构:

struct data {
    int something;
};

struct container {
    int something_before;
    struct data data_item;
    int something_after;
};

假设您有一个指向struct data值的指针:

struct data *data_ptr;

list_entry()宏可帮助您将data_ptr转换为指向struct container值的指针,该值包含struct data指向的值ptr:< / p>

struct container *cont_ptr = list_entry(data_ptr, struct container, data_item);

宏通过计算data_itemstruct container的偏移量,并从data_ptr指针中减去那么多字节来工作。当转换为struct container *时,这会向struct container提供一个有效指针,该指针将struct data“置于”内部“。

使用内置offsetof()宏:

也可以简化宏
#define list_entry(ptr, type, member) \
    ((type *)((char *)(ptr) – offsetof(type, member)))

答案 1 :(得分:10)

答案 2 :(得分:2)

此宏用于查找给定其成员之一的结构的地址。

因此,例如,假设你有结构:

typedef struct
{
    int i;
    int j;
} typestruct;

你需要知道的第一件事是宏的最后一部分:

 &((typestruct *)0)->j

用于给出成员的偏移量。因此,它是从类型的内存到成员的大小(以字节为单位)。在这种情况下,它是sizeof(int),因为j正好是int i;因此,为简单起见,我们假设此表达式值为4。您可以使用宏

获得相同的结果
offsetof(typestruct, j);

现在我们想要计算temp的地址,其中temptypestruct temp。为此,我们简单地计算指针的地址减去成员位置。指针的地址是:

(typestruct *)((char *) &temp.j)

因此,减法是:

&temp ==  (typestruct *)((char *) &temp.j) - offsetof(typestruct, j)

或者像宏说的那样:

&temp ==  (typestruct *)((char *) &temp.j) - &((typestruct *)0)->j

您可以了解更多here以及此question

(括号是必要的,但为了澄清而被删除)