Подтвердить что ты не робот

Почему это 0 в ((type *) 0) → член в C?

Макрос container_of() в ядре Linux определяется как:

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

Почему это использует ((type*)0)->member, а не (type*)->member?

4b9b3361

Ответ 1

Почему это ((type *) 0) → member, not (type *) → member

Просто потому, что (type*)->member будет недопустимым синтаксисом, поэтому typeof будет невозможно. Поэтому он использует указатель NULL, который он не разыскивает в любом случае - он используется так, чтобы typeof мог ссылаться на член.


Как это работает:

  • Тройка typeof используется для объявления указателя типа элемента. Этот указатель получает инициализируется указателем, переданным вызывающим абонентом

  • Смещение этого члена в структуре вычитается из адреса указателя: это дает адрес содержащего объекта


Проблема с Subtler: почему бы не избавиться от typeof и просто сделать ptr - offsetof. Мы все равно отбрасываем его на char *, верно? В этом случае вы можете передать что-либо как ptr, и компилятор ничего не скажет. Итак, все вещи typeof существуют для (рудиментарного) контроля типов.

Ответ 2

Потому что type* - это тип, а не действительный экземпляр структуры.

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