помогите разобраться в макросе (надо понять как работает макрос container_of(, объявленный в ядре)

Модератор: Модераторы разделов

чудо
Сообщения: 11

помогите разобраться в макросе

Сообщение чудо »

из ядра 2.6.6
макрос объявлен в linux/kernel.h
используется для получения структуры из содержащей ее структуры
в частности многие структуры в ядре связаны списками типа struct list_head,которые ничего не содержат,кроме указателей на следующий и предыдущий элемент.
этот макрос должен извлекать структуру по указателю,типу структуры и имени члена в структуре

#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

как понимать выражение ((type *)0)->member?
и что такое __mptr?

еще нашел,что такое offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

если можете,поясните максимально днтально работу макроса container_of
спасибо.
Спасибо сказали:
_petya_
Сообщения: 53

Re: помогите разобраться в макросе

Сообщение _petya_ »

Макрос возвращает указатель на начало структуры типа type .При этом предплагается, что ptr указывает на поле member этой структуры.
К примеру, при создании индекса (inode) для сокета создаётся структура
struct socket_alloc {
struct socket socket;
struct inode vfs_inode;
}
При этом функции, создавшей индекс, возвращается указатель на vfs_inode.
В дальнейшем, функциям, работающим с этим сокетом через индекс, может понадобиться доступ к структуре socket_alloc в целом или к структуре socket.
Тогда будет сделано так
/*inode -указатель на индекс сокета (на поле vfs_inode структуры socket_alloc)*/
struct socket *s = container_of(inode,socket_alloc,vfs_inode)->socket;

По строчкам:
const typeof( ((type *)0)->member ) *__mptr = (ptr);
Выражение typeof( ((type *)0)->member ) возвращает тип поля, на который указывает ptr. Выглядит действительно жутко, но работает - компилятор всё понимает и ошибок времени выполнения нет.
__mptr - просто имя переменной.

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
Макрос возвращает адрес поля MEMBER. Так как указатель на структуру, содержащую поле, равен 0, то адрес поля MEMBER - это его (поля) смещение от-но начала структуры .

(type *)( (char *)__mptr - offsetof(type,member) );
Эта строчка вычитает из адреса поля member его (поля) смещение, и получается адрес содержащей его стр-ры.

P.S. Сам недавно начал бродить по ядру - там много прикольных вещей вроде ((type *)0)->member
Спасибо сказали: