Запросить объяснение макроса ядра: hlist_nulls_for_each_entry

Меня смущает определение функции ядра Linux. hlist_nulls_for_each_entry определяется как цикл for, и его легко понять.

#define hlist_nulls_for_each_entry(tpos, pos, head, member)            \
    for (pos = (head)->first;                          \
         (!is_a_nulls(pos)) &&                         \
        ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \
         pos = pos->next)

Хотя я не могу понять следующее предложение, почему автор добавляет ; 1; до конца. Почему бы не переместить предложение tpos = hlist_nulls_entry(pos, typeof(*tpos), member) в следующее из pos = pos->next .

 ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;});

person river    schedule 10.02.2018    source источник


Ответы (1)


Это составное утверждение. Последний 1 существует, так что значение блока операторов оценивается как 1, что делает условие истинным.

Из документации

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

Здесь, независимо от того, что окажется присвоенным значением tpos, мы хотим выполнить цикл for. Вот почему там 1;. Цикл остановится на другом указанном условии, а именно (!is_a_nulls(pos)).

Да, вы можете переместить его с операцией увеличения, также разделенной запятой. Мы также можем отформатировать цикл, чтобы сделать это. Но помните, что здесь мы также запускаем цикл для начального значения, поэтому нам нужно поработать с ним до того, как будет выполнено увеличение.

Обратите внимание, что это расширение gcc. Стандарт C не предлагает этого. Это означает, что это не портативное решение. Если вы напишете его в том же старом блоке цикла for, вам будет хорошо работать, основываясь на переносимости.

person user2736738    schedule 10.02.2018