List_entry в Linux
user/include/linux/list.h
это объявление:
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr) – (unsigned long)(&((type *)0)->member)))
может кто-нибудь объяснить, что это такое и как он работает, заранее спасибо
P.S. пожалуйста, упростите свой ответ в максимально возможной степени, я знаю о потоках, процессах в Linux, теперь я изучаю возможности, и я немного застрял с этим.
Ответы
Ответ 1
Рассмотрим две такие структуры:
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
:
struct container *cont_ptr = list_entry(data_ptr, struct container, data_item);
Макрос работает, вычисляя смещение data_item
внутри struct container
и вычитая, что много байтов указателя data_ptr
. Это при приведении к struct container *
дает действительный указатель на struct container
, который содержит этот конкретный struct data
"внутри".
Макрос можно также немного упростить, используя встроенный макрос offsetof()
:
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr) – offsetof(type, member)))
Ответ 2
Объяснение этого вы найдете здесь: Раздел Как это работает?
Ответ 3
Этот макрос используется для нахождения адреса структуры, заданной одним из его членов.
Итак, предположим, что у вас есть struct:
typedef struct
{
int i;
int j;
} typestruct;
Прежде всего вам нужно знать, что последняя часть макроса:
&((typestruct *)0)->j
Используется для смещения члена. Таким образом, это размер в байтах из нулевой памяти, переданной типу, члену. В этом случае это sizeof(int)
, потому что j
просто ниже int i
; Поэтому давайте предположим это выражение 4
для простоты. Вы можете получить тот же результат с макросом
offsetof(typestruct, j);
Теперь мы хотим вычислить адрес temp
, где temp
- typestruct temp
. Для этого мы просто вычислим адрес указателя минус позиция элемента. Адрес указателя:
(typestruct *)((char *) &temp.j)
Следовательно, вычитание:
&temp == (typestruct *)((char *) &temp.j) - offsetof(typestruct, j)
или, как макрос говорит:
&temp == (typestruct *)((char *) &temp.j) - &((typestruct *)0)->j
Вы можете узнать гораздо больше здесь, а также в этом question.
(Скобки необходимы, но устранены для пояснения)