我正在研究两个链表实现(queue.h[source]和utlist.h[source](,我对它们各自的实现有一些问题:
_Q_INVALIDATE
在queue.h中的作用是什么?我想这是一些调试的一部分,但我并不真正理解宏define
逻辑- 这两种实现都提供了
FOREACH
和FOREACH_SAFE
。前者是直截了当的,但后者背后的逻辑是什么?此外,如果前者无论如何都是不安全的,为什么一开始就实施它 - 为什么
queue.h
将其结构实现为具有不同类型的next
和prev
(struct *le_next
和struct **le_prev
( - 在这两种实现中,为什么在这里和那里都插入了额外的括号?例如
#define LIST_FIRST(head) ((head)->lh_first)
中的head
附近
对于问题1:
_Q_INVALIDATE
是一个宏,它将不应再使用的指针设置为值-1
。这样做的目的是,如果以后使用它,调试将变得更容易,因为使用指针会导致立即崩溃。在非调试模式下,宏什么都不做,所以指针只保留其当前值——如果有错误导致指针被使用,那么问题可能是一个更微妙的缺陷。
问题2:
这些宏的"安全"版本采用了一个额外的指针参数,在处理当前项时,宏在内部使用该参数来指向列表中的下一项。这允许循环中的代码从列表中删除当前项。由于下一项已经在临时指针中被记住,因此宏在下一次迭代中拾取它没有问题。该宏的非安全版本不使用临时指针,因此在迭代时无法从列表中删除当前项。
问题3:
这使得在当前元素之前添加新元素或从列表中删除当前元素变得更容易,而不必担心当前元素是否位于列表的开头(因此仅由列表指针"指向"(,或者当前元素是否在列表的其他位置(因此由另一个元素的le_next
指针指向(。如果le_prev
是struct type*
,那么处理列表中的第一个元素将需要特殊情况代码。由于le_prev
是struct type**
,它可以像嵌入在type
内部某个任意偏移处的struct type*
一样容易地引用简单的struct type*
(如列表头指针((如每个元素中的le_next
链接(。
上面的评论回答了问题4。