Linux 中的 list_entry

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5550404/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:31:50  来源:igfitidea点击:

list_entry in Linux

clinuxlinux-kernel

提问by likeIT

user/include/linux/list.h

this declaration:

本声明:

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

can somebody please explain what is this and how does it work, thanks in advance

有人可以解释一下这是什么以及它是如何工作的,在此先感谢

P.S. please simplify your answer as much as possible, I know about threads, processes in Linux, now I'm exploring possibilities and I'm a little bit stuck with this one.

PS,请尽可能简化您的答案,我了解 Linux 中的线程和进程,现在我正在探索各种可能性,但我对这个问题有点困惑。

采纳答案by Petri Lehtinen

Consider two structs like this:

考虑两个这样的结构:

struct data {
    int something;
};

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

Assume you have a pointer to a struct datavalue:

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

struct data *data_ptr;

The list_entry()macro helps you to convert data_ptrto a pointer to the struct containervalue that holds the struct datavalue, pointed to by ptr:

list_entry()宏可帮助您转换data_ptr为指向struct container保存该struct data值的值的指针,指向ptr

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

The macro works by computing the offset of data_iteminside the struct container, and subtracting that many bytes from the data_ptrpointer. This, when cast to struct container *, gives a valid pointer to the struct containerthat holds this particular struct data"inside".

宏的工作原理是计算data_item内部的偏移量struct container,然后从data_ptr指针中减去那么多字节。This,当转换为 时struct container *,会给出一个有效的指针,指向struct container包含此特定struct data“内部”的 。

The macro can also be simplified a bit by using the builtin offsetof()macro:

宏也可以通过使用内置offsetof()宏来简化一点:

#define list_entry(ptr, type, member) \
    ((type *)((char *)(ptr) – offsetof(type, member)))

回答by stacker

An explanation of this you find here: Section How Does This Work?

您可以在此处找到对此的解释:这是如何工作的部分?

回答by Dr Beco

This macro is used to find the address of a struct given one of its member.

该宏用于在给定其成员之一的情况下查找结构的地址。

So, for example, suppose you have the struct:

因此,例如,假设您有以下结构:

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

First thing you need to know is that the last part of the macro:

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

 &((typestruct *)0)->j

Is used to give the offset of a member. So, it is the size, in bytes, from the zeromemory casted to the type, to the member. In this case, it is the sizeof(int), because jis just bellow int i; So lets assume this expression values 4for simplicity. You can get the same result with the macro

用于给出成员的偏移量。因此,它是从内存转换为类型到成员的大小(以字节为单位)。在这种情况下,它是sizeof(int),因为j就在下面int i;所以4为了简单起见,让我们假设这个表达式值。您可以使用宏获得相同的结果

offsetof(typestruct, j);

Now we want to calculate the address of temp, where tempis typestruct temp. To do that, we simple compute the address of the pointer minus the member position. The address of the pointer is:

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

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

Hence, the subtraction is:

因此,减法是:

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

or, like the macro says:

或者,就像宏说的:

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

You can learn much more here, and also in this question.

您可以在此处以及在此问题中了解更多信息

(Parenthesis are necessary, but was eliminated for clarification)

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