Понимание контейнера макросов в ядре Linux
когда я просматривал ядро Linux, я нашел container_of макрос, который определяется следующим образом:
#define container_of(ptr, type, member) ({
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
Я понимаю, что делает container_of, но то, что я не понимаю, это последнее предложение, которое
(type *)( (char *)__mptr - offsetof(type,member) );})
если мы используем макрос следующим образом:
container_of(dev, struct wifi_device, dev);
соответствующая часть последнего предложения будет:
(struct wifi_device *)( (char *)__mptr - offset(struct wifi_device, dev);
, который выглядит, как ничего не делать.
Кто-нибудь может заполнить пустоту здесь?
4 ответов:
ваш пример использования
container_of(dev, struct wifi_device, dev);может быть немного вводит в заблуждение, как вы смешиваете здесь два пространства имен.в то время как первый
devв вашем примере ссылается на имя указателя второйdevотносится к имени элемента структуры.скорее всего, эта путаница провоцирует всю эту головную боль. На самом деле
memberпараметр в вашей цитате ссылается на имя, данное этому члену в структуре контейнера.принимая этот контейнер для пример:
struct container { int some_other_data; int this_data; }и указатель
int *my_ptrдоthis_dataвы бы использовать макрос, чтобы получить указатель наstruct container *my_containerиспользование:struct container *my_container; my_container = container_of(my_ptr, struct container, this_data);принимая смещение
this_dataк началу структуры во внимание имеет важное значение для получения правильного расположения указателя.фактически вам просто нужно вычесть смещение члена
this_dataот указателяmy_ptrчтобы получить правильное расположение.это именно то, что последнее строка макроса.
последнее предложение приведено:
(type *)(...)указатель на заданное
type. Указатель вычисляется как смещение от заданного указателяdev:( (char *)__mptr - offsetof(type,member) )при использовании
cointainer_ofмакрос, вы хотите получить структуру, которая содержит указатель на данное поле. Например:struct numbers { int one; int two; int three; } n; int *ptr = &n.two; struct numbers *n_ptr; n_ptr = container_of(ptr, struct numbers, two);у вас есть указатель, который указывает в середине структуры (и вы знаете, что это указатель на поданную
two[имя поля в структура]), но вы хотите получить всю структуру (numbers). Итак, вы вычисляете смещение поданногоtwoв структуру:offsetof(type,member)и вычесть это смещение из заданного указателя. Результатом является указатель на начало структуры. Наконец, вы приводите этот указатель к типу структуры, чтобы иметь допустимую переменную.
это использование расширения gcc,высказывания выражения. Если вы видите макрос как что-то возвращающее значение, то последняя строка будет :
return (struct wifi_device *)( (char *)__mptr - offset(struct wifi_device, dev);см. связанную страницу для объяснения составных операторов. Вот пример :
int main(int argc, char**argv) { int b; b = 5; b = ({int a; a = b*b; a;}); printf("b %d\n", b); }выход
b 25
немного реальный контекст говорит яснее, ниже используйте красно-черное дерево в качестве примера, который является так что я понимаю
container_of.как
Documentation/rbtree.txtсостояния, в коде ядра linux, это не rb_node содержат данные вход, скорееузлы данных в дереве rbtree-это структуры, содержащие структуру член rb_node.
struct vm_area_struct(в файлеinclude/linux/mm_types.h:284) - это такая структура,в то же файл, есть макрос
rb_entry, который определяется как#define rb_entry(ptr, type, member) container_of(ptr, type, member)понятно,
rb_entryтакой же, какcontainer_of.at
mm/mmap.c:299внутри определения функцииbrowse_rbесть использованиеrb_entry:static int browse_rb(struct mm_struct *mm) { /* two line code not matter */ struct rb_node *nd, *pn = NULL; /*nd, first arg, i.e. ptr. */ unsigned long prev = 0, pend = 0; for (nd = rb_first(root); nd; nd = rb_next(nd)) { struct vm_area_struct *vma; vma = rb_entry(nd, struct vm_area_struct, vm_rb); /* -- usage of rb_entry (equivalent to container_of) */ /* more code not matter here */теперь понятно, в
container_of(ptr, type, member),
typeэто структура контейнера, здесьstruct vm_area_structmember- это имя членаtypeнапример, здесьvm_rbтипаrb_node,ptrэто указатель, указывающийmemberнаtypeнапример, здесьrb_node *nd.что
container_ofсделать это, как в данном примере,
- данный адрес
obj.member(здесьobj.vm_rb), вернуть адресobj.- поскольку структура является блоком непрерывной памяти,адрес
obj.vm_rbминусoffset between the struct and memberбудет адрес контейнера.
include/linux/kernel.h:858-- определениеcontainer_of
include/linux/rbtree.h:51-- определениеrb_entry
mm/mmap.c:299-- использованиеrb_entry
include/linux/mm_types.h:284--struct vm_area_struct
Documentation/rbtree.txt:-- документация красно-черного дерева
include/linux/rbtree.h:36-- определениеstruct rb_nodeП. С.
вышеуказанные файлы находятся в текущей версии разработки, т. е.
4.13.0-rc7.
file:kозначает K-ю строку вfile.
Comments