链表在libnet中的实现

list链表是双链表,在libnet中的实现同样简单,其借用了linux中list的实现思路,将指针域与数据域分离。要用list也是跟list中一样的。

如下是指针域的实现代码——为了方便阅读,我用linux下的风格将语句分开了。

/* Linked list code, inspired by Links, but written from scratch. */

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

#define init_list(L) \
do { \
L.next
= L.prev = &L; \
}
while (0)

#define list_empty(L) (L.next == &L)

#define add_to_list(L, n) \
do { \
n
->next = L.next; \
n
->next->prev = n; \
n
->prev = (void *) &L; \
L.next
= n; \
}
while (0)

#define append_to_list(L, n) \
do {                   \
n
->prev = L.prev; \
n
->prev->next = n; \
n
->next = (void *) &L; \
L.prev
= n; \
}
while (0)

#define del_from_list(n) \
do { \
n
->prev->next = n->next; \
n
->next->prev = n->prev; \
}
while (0)

#define foreach(n, L) \
for (n = L.next; \
n
!= (void *) &L; \
n
= n->next) \

#define free_list(L, dtor) \
do { \
struct list_head *x, *y; \
for (x = L.next; \
x
!= (void *) &L; \
x
= y) \
{ \
y
= x->next; \
dtor ((
void *) x); \
} \
init_list (L); \
}
while (0)

代码没有任何注释,但是也还算清晰,有几点需要注意的

1)#define MACRO_NAME(para) do{macro content}while(0)

参考文章 在宏定义中使用 do...while

此处的用处显然是第三种

/*使用do{….}while(0) 把它包裹起来,成为一个独立的语法单元,从而不会与上下文发生混淆。
同时因为绝大多数的编译器都能够识别do{…}while(0)这种无用的循环并进行优化,所以使用这种
方法也不会导致程序的性能降低。
*/
2)该实现非常简单,foreach循环的时候,不是安全的(不能删除,只能遍历),参见linux有xxx_safe的遍历。

3)链表未循环双链表,但是插入只能在头和尾操作(对应add和append);删除将自己从链表中剥离(不涉及到内存的释放),该节点可以是链表任意节点。

4)释放链表传递了一个dtor函数,这要求用户自己实现——但是其没有提供检查机制,非常危险。

最后不推荐此种方式,关于宏的弊病此处不做讨论。

原文地址:https://www.cnblogs.com/westfly/p/2006993.html