libevent中的tailq本質上, 就是一個雙向鏈表, 而後記錄下了頭指針和尾指針, 便於順序遍歷和逆序遍歷.spa
因爲C語言中沒有模板, 爲了適應不一樣的數據類型, tailq的操做, 都是使用的宏定義, 致使代碼難以閱讀.指針
爲了方便分析, 本文對tailq相關的結構體進行了簡化:code
struct tailq{ struct element* first; struct element** last; };
struct element{ struct element* next; //next必須放在第一個位置 struct element** prev; int x;//這裏表示結構體中的其它成員 };
讀者可能有如下一些疑問:element
1. last和prev爲何要使用指針地址, 直接用struct element*不是更簡潔明瞭嗎?event
看下面這段代碼: ast
struct element** prev; struct element* elem = malloc(sizeof(struct element)); prev = &elem->next;
根據C語言的規則模板
由於elem == &elem->nextclass
因此: prev == elem效率
即: next的值elem指針, prev的值也是elem的指針, 只不過形式上是struct element**, 使用時, 能夠直接強轉爲struct elemnt*來操做遍歷
寫了一個普通的雙向鏈表, 與之對比, 得出的結論是, tailq使用指針地址方式, insert_tail的操做少了一條if語句判斷, 效率上更優.
2. 數據存儲的結構是怎樣的, 根據代碼表面上的意義, 能夠畫出這樣一張圖:
綠色表示整個element
藍色表示字段
白色表示值
因爲&next的值, 等於element指針, 因此上圖能夠演變成
這樣, 就很清晰了, prev指向前一個元素, next指向後一個元素, first指向第一人元素, last指向最後一個元素