Расширение макроса C в коде ядра Linux - PullRequest
6 голосов
/ 20 апреля 2010

Я обычно игнорировал использование макросов при записи в C , но я думаю, что знаю о них основы. Пока я читал исходный код списка в ядре Linux, я увидел нечто подобное:

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
    struct list_head name = LIST_HEAD_INIT(name)

(Вы можете получить доступ к оставшейся части кода с здесь. )

Я не понял функцию амперсандов (я не думаю, что они здесь являются адресами операндов) в LIST_HEAD_INIT и, следовательно, в LIST_HEAD_INIT в коде. Буду признателен, если кто-нибудь сможет меня просветить.

Ответы [ 5 ]

15 голосов
/ 20 апреля 2010

Чтобы знать, что на самом деле происходит, нам нужно определение struct list_head:

struct list_head {
        struct list_head *next, *prev;
};

Теперь рассмотрим макросы:

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)

Если в коде, который я пишу, LIST_HEAD(foo), он будет расширен до:

struct list_head foo = { &(foo) , &(foo)}

, который представляет пустой двусвязный список с узлом заголовка , где указатели next и prev указывают на сам узел заголовка.

Это то же самое, что и:

struct list_head foo;
foo.next = &foo;
foo.prev = &foo;

Таким образом, эти макросы позволяют инициализировать двусвязный список.

И да, & используется здесь как адрес оператора.

EDIT:

Вот это working example

По предоставленной вами ссылке. Вы имели:

struct list_head test = LIST_HEAD (check);

что неверно. Вы должны иметь:

LIST_HEAD (check);
8 голосов
/ 20 апреля 2010

Каждый раз, когда вы сомневаетесь в том, что на самом деле делает макрос, вы можете попросить 'gcc -E' расширить его для вас.

В этом случае он просто инициализирует структуру списка с указателями на себя.

3 голосов
/ 20 апреля 2010

Они являются адресами операторов здесь. Связанные списки в ядре избегают нулевых указателей, обозначающих конец списка. Поэтому заголовок должен быть инициализирован с некоторым допустимым указателем. В этой реализации, если указатель «head» или «tail» указывает на адрес заголовка списка, список считается пустым.

1 голос
/ 20 апреля 2010

Кажется, что сам макрос не используется в list.h.

Полагаю, & действительно означают адреса в коде. struct list_head содержит два указателя, поэтому для объявления struct list_head name = LIST_HEAD_INIT(name) (см. Макрос LIST_HEAD) вполне естественно получить пару указателей в качестве инициализатора.

0 голосов
/ 20 апреля 2010

Это именно то, что они есть, амперсанды берут адрес параметра и сохраняют их как в полях списка «заголовок», так и в поле «следующий». Не могу сказать почему, так как я не нашел фактического использования этого макроса, но это то, что он делает.

...