linux的宏定義提高了代碼的簡潔性,但有時候的命名不夠完美。比如list_for_each_entry,看名字只知道是遍歷list,但一看里面的三個變量參數,有點懵逼。
/**
* list_for_each_entry ?- ? ? ? iterate over list of given type
* @pos: ? ? ? ?the type * to use as a loop cursor.
* @head: ? ? ? the head for your list.
* @member: ? ? the name of the list_head within the struct.
*/
#define list_for_each_entry(pos, head, member) ? ? ? ? ? ? ? ? ? ? ? ? ?\
for (pos = list_first_entry(head, typeof(*pos), member); ? ? ? ?\
!list_entry_is_head(pos, head, member); ? ? ? ? ? ? ? ? ? ?\
pos = list_next_entry(pos, member))
誰是given type? 被遍歷的是誰?咋看看不出來。
/**
* list_first_entry - get the first element from a list
* @ptr: ? ? ? ?the list head to take the element from.
* @type: ? ? ? the type of the struct this is embedded in.
* @member: ? ? the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
這個宏的comments解釋說是獲取一個list的第一個元素。 但是一看宏定義有點懵,怎么又來一個宏在里面?
/**
* list_entry - get the struct for this entry
* @ptr: ? ? ? ?the &struct list_head pointer.
* @type: ? ? ? the type of the struct this is embedded in.
* @member: ? ? the name of the list_head within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
這個宏定義看解釋是獲取當前entry的所屬結構體,又來一個宏:
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
* WARNING: any const qualifier of @ptr is lost.
*/
#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
?此宏就是,給了一個結構體變量的其中成員變量,而獲取此結構體變量的地址。ptr是成員變量地址,type是結構體類型,member是成員變量在結構體聲明里的名字稱謂。
所以說?list_entry 是獲取ptr所屬的結構體地址。list_first_entry 是獲取(ptr)->next 所在結構體的地址,
而list_for_each_entry里面還有宏:
/**
* list_entry_is_head - test if the entry points to the head of the list
* @pos: ? ? ? ?the type * to cursor
* @head: ? ? ? the head for your list.
* @member: ? ? the name of the list_head within the struct.
*/
#define list_entry_is_head(pos, head, member) ? ? ? ? ? ? ? ? ? ? ? ? ? \
(&pos->member == (head))
這個宏名字取的更敷衍。解釋內容說是為了驗證是不是list的頭指針。 看代碼是驗證pos這個結構體的成員member地址是不是和head一樣。
再看另外一個宏:
/**
* list_next_entry - get the next element in list
* @pos: ? ? ? ?the type * to cursor
* @member: ? ? the name of the list_head within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)
解釋內容說是獲取list的下一個成員指針,看代碼是獲取(pos)->member.next 所在結構體的地址。
這樣整體來看:
#define list_for_each_entry(pos, head, member) ? ? ? ? ? ? ? ? ? ? ? ? ?\
for (pos = list_first_entry(head, typeof(*pos), member); ? ? ? ?\ //獲取head->next所在結構體地址給pos
!list_entry_is_head(pos, head, member); ? ? ? ? ? ? ? ? ? ?\//判斷pos的member成員地址是否和head一樣,如果一樣,就跳出循環
pos = list_next_entry(pos, member))? ?//獲取(pos)->member.next 所在結構體的地址
綜上所述,這里遍歷了一個循環鏈表,表頭是head,但是似乎head沒被拿來遍歷到?直接從head->next開始的?遍歷到再次碰到head的地址就結束了,即表明遍歷了一圈了。?member就是鏈表個成員(鏈表類型地址)內含的內容地址。這里head為什么是廢棄的?