C: Что означает этот макрос? - PullRequest
4 голосов
/ 21 ноября 2011

Как вы читаете вторую строку этого макроса?Что означает (тип *) 0 в этом контексте?

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

Ответы [ 5 ]

4 голосов
/ 21 ноября 2011

Вы находите тип из ((type *)0)->member. На самом деле это не разыменование указателя (это было бы безумием, говорю вам. Безумие! )

Это странность C. Может быть, имело бы больше смысла, если бы они написали typeof(type.member), но, к сожалению, это не разрешено.

3 голосов
/ 21 ноября 2011

Чуть более читаемая версия:

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

Короче говоря, макрос определяет полезный «тест», который можно вставить в оператор if и другие. ((Type *) 0) преобразует NULL-ссылку в рассматриваемый тип, а затем принимает подкомпонент 'member' типа. Макрос typeof () вернет тип, связанный с подэлементом «object». Таким образом, создается постоянная переменная __mptr того же типа, что и подкомпонент type.member. Например, если бы мы имели:

typedef struct foo_s {
   int bogus;
   int bar;
} foo;

Тогда, если вызвать так:

foo blah;  /* and initialize it of course */
int *myptr = &foo.bar;

foo *result = container_of(myptr, foo, bar);

Тогда первая строка макроса превратится в следующее:

const int *__mptr = (myptr);

Затем вторая строка макроса вычисляет позицию в памяти исходной структуры, возвращает указатель памяти структуры и правильно переводит его в эту структуру, а расширенное значение будет выглядеть так:

(foo *)( (char *)__mptr - offsetof(foo, bar));

Результат таков:

foo *result = container_of(myptr, foo, bar);

позволяет вам взять элемент myptr внутри структуры и извлечь из него указатель на исходный контейнер.

Теперь, в приведенном выше примере это бесполезно, потому что у вас уже есть доступ к вмещающей структуре. Но сделайте вид, что вы этого не сделали, потому что API, в котором вы находитесь, не прошел его. Этот макрос - хитрый способ получить родительский контейнер, если у вас его обычно не было бы.

Лучше всего, конечно, создать лучший API, где этот хак не нужен. Но это полезно, если вы c

1 голос
/ 21 ноября 2011

На самом деле вторая строка избыточна и предназначена только для проверки типов.

#define container_of(ptr, type, member) ({\ 
 (type *)( (char *)ptr - offsetof(type,member) );}) 

будет иметь ту же семантику, за исключением возможности проверки типа.

Посмотрите на: Обоснование за макросом container_of в linux / list.h

См. Также общее объяснение: http://www.kroah.com/log/linux/container_of.html

1 голос
/ 21 ноября 2011

Это так же, как определяется offsetof (тип, член).

# определение offsetof (TYPE, MEMBER) ((size_t) & ((TYPE *) 0) -> MEMBER)

(TYPE *) 0 переводит 0 в указатель, указывающий на 0 типа TYPE, а ((TYPE *) 0) -> элемент указывает на член TYPE.

1 голос
/ 21 ноября 2011

(type *)0 по существу NULL.Вторая строка берет адрес значения, которое вы ему дали, и вычитает его позиции в структуре.который дает вам адрес структуры

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...