我们在 NS2 中的基类中经常会看到宏 LIST_HEAD,LIST_ENTRY 等宏,它们实现此类的实体的链表,举一个例子 Node 类就是一个例子, 在 node.h 中有如下定义有如下代码
注意: 代码省略了不相关部分代码
LIST_HEAD(node_head, Node);
// 声明链表的头节点结构体 node_head ,仅含有 Node 型指针 lh_first 一个
class Node : public ParentNode {
public:
static struct node_head nodehead_; // static head of list of nodes
inline void insert(struct node_head* head) {
LIST_INSERT_HEAD(head, this, entry);
}
inline Node* nextnode() { return entry.le_next; }
protected:
LIST_ENTRY(Node) entry;
// 声明链表指针实体部分,含有两个指针
}
Node 类的实例可以通过结构体变量 entry 里包含的两个 Node* 类型的指针来链接成一个链表。
由于 NS 软件的特点,我们经常需要读各种组件的代码,以及修改代码,这样对于常用的结构我们必须了解,比如在函数 dump 中的 ifhead_.lh_first ,如果我们每次遇到这样的结构都去查找,那么工作量会很大,并且会发现我们总是需要跳转多个文件才可一最终弄通当前的代码含义。
void MobileNode::dump(void)
{
Phy *n;
fprintf(stdout, "Index: %d/n", address_);
fprintf(stdout, "Network Interface List/n");
for(n = ifhead_.lh_first ; n; n = n->nextnode() )
n->dump();
fprintf(stdout,/ "--------------------------------------------------/n");
}
所以了解这些宏的含义,和系统已经定义的各种宏就很有必要,下边我们介绍宏的定义以及代码分析。
ns2 里最常用的宏链表定义在文件 ns-2.31/lib/bsd-list.h 中,其功能很是大 , 下边是详细代码分析
// 头节点宏
// 链表单指针头节点结构体宏
#define LIST_HEAD(name, type)
struct name {
type *lh_first; /* first element */
}
// 链表实体用于连接的指针部分、 可在某个类的定义中声明该结构题的实体,就可以用此链表连接此类的实体了
#define LIST_ENTRY(type)
struct {
type *le_next; /* next element */
type **le_prev; /* address of previous next element */
// le_next 指向下一个节点, le_prev 指向前面节点的 “ next element” 的地址,“ next elemnet “ 为 lh_first 或者 le_next 这样用发就同一了接口,实在是高
}
// 初始化连表 struct name * head
#define LIST_INIT(head) {
(head)->lh_first = NULL;
}
/* 变量说明:
struct name * head, 指向链表的头节点
listelm, elm 为指向一个类 / 实体的指针
field 为此 elm 的 LIST_ENTRY 实体
特别注意 le_prev 的处理与众不同,他是二级 指针变量
*/
// 尾插法 elm 插入到 listelm 后 使用的指针在 field 中
#define LIST_INSERT_AFTER(listelm, elm, field) {
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)
(listelm)->field.le_next->field.le_prev =
&(elm)->field.le_next;
(listelm)->field.le_next = (elm);
(elm)->field.le_prev = &(listelm)->field.le_next;
}
// 前插法 , elm 插入到 listelm 前
#define LIST_INSERT_BEFORE(listelm, elm, field) {
(elm)->field.le_prev = (listelm)->field.le_prev;
(elm)->field.le_next = (listelm);
*(listelm)->field.le_prev = (elm);
(listelm)->field.le_prev = &(elm)->field.le_next;
}
// 头插法 elm 插入到 head 后边
#define LIST_INSERT_HEAD(head, elm, field) {
if (((elm)->field.le_next = (head)->lh_first) != NULL)
(head)->lh_first->field.le_prev = &(elm)->field.le_next;
(head)->lh_first = (elm);
(elm)->field.le_prev = &(head)->lh_first; // 指向指针的指针
}
// 删除 elm ,由于是双向链表,参数只有两个就可以了
#define LIST_REMOVE(elm, field) {
if ((elm)->field.le_next != NULL)
(elm)->field.le_next->field.le_prev =
(elm)->field.le_prev;
*(elm)->field.le_prev = (elm)->field.le_next;
}