您的位置:首页 > 运维架构 > Linux

对linux_list中宏和函数的理解[part1 基本使用]

2016-09-30 14:34 369 查看
Part1 基本使用

@1.宏

#1.offsetof

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

TYPE~结构体

MEMBER~结构体成员

(TYPE *)0)~ 把0地址强转为TYPE类型的结构体

&((TYPE *)0)->MEMBER)~取结构体中该成员的地址,即该成员相对于结构体的地址偏移量

’ . ’ address.offset = address.member - address.struct

’ . ’ address.struct = 0

’ : ’ address.offset = address.member

*& 该宏返回指定结构体类型中某个成员相对于结构体的偏移量

#2.container_of

#define container_of(ptr, type, member) ({ **

const typeof( ((type *)0)->member ) *__mptr = (ptr); \

(type )( (char )__mptr - offsetof(type,member) );})

ptr~结构体成员地址

type~结构体类型

member~结构体成员

typeof( ((type *)0)->member ) *__mptr = (ptr)~定义变量__mptr和ptr同一类型指针,并且都指向结构体成员member

(type )( (char )__mptr - offsetof(type,member) )~结构体成员地址减掉自己和结构体的偏移,即构体的地址

’ . ’ address.struct + address.offset = address.member

’ : ’ address.struct = address.member - address.offset

*&该宏由结构体成员的地址返回结构体的地址

*? 这里为什么要重新定义一个变量,而不直接用ptr呢?



#3.list_head

struct list_head {

struct list_head *next, *prev;

};

* & 结构体list_headlist_head有两个结构体成员,均是该结构体类型的指针

**#4. LIST_HEAD_INIT

#define LIST_HEAD_INIT(name) { &(name), &(name) }

name~ 结构体**

&(name)~指向结构体的指针

*&该宏返回两个指向结构体的指针

#5.LIST_HEAD

*#define LIST_HEAD(name) *

struct list_head name = LIST_HEAD_INIT(name)

name~结构体

LIST_HEAD_INIT(name)~返回两个指向name的指针

*& 将结构体name前两个成员初始化为指向自己的指针,这里的结构体一般指list_head类型的,其作用和#6一样

#6.INIT_LIST_HEAD

*#define INIT_LIST_HEAD(ptr) do { *

(ptr)->next = (ptr); (ptr)->prev = (ptr); \

} while (0)

ptr~list_head类型结构体指针

*&将结构体的next和prev指针均指向自己本身,通常作为list_head头节点的初始化,作用和#5一样

#7.list_entry

*#define list_entry(ptr, type, member) *

container_of(ptr, type, member)

*&等价于#2

#8.list_for_each_entry

*#define list_for_each_entry(pos, head, member) *

for (pos = list_entry((head)->next, typeof(*pos), member); \

&pos->member != (head); \

pos = list_entry(pos->member.next, typeof(*pos), member))

pos = list_entry((head)->next, typeof(*pos), member)~已知结构体成员的地址,将头节点的下一个元素的地址返回给pos

&pos->member != (head)~for语句的判断条件,pos现在不等于头节点

pos = list_entry((head)->next, typeof(*pos), member)~pos等于当前的下一个节点

*&从head的下一个元素开始遍历,每次pos都会指向当前的节点,直到pos指向head,正好遍历完除头节点之外的所有节点,所以头结点一般数据域无效

@2.函数

#1.__list_add

static inline void __list_add(struct list_head *new,

struct list_head *prev,

struct list_head *next)

{

next->prev = new;

new->next = next;

new->prev = prev;

prev->next = new;

}

*& 将结构new插入到结构prev和next中间



#2.list_add

static inline void list_add(struct list_head *new, struct list_head *head)

{

__list_add(new, head, head->next);

}

*& 将new结构加入到head的后面,即右边,若head为头节点,则遍历会是逆序的遍历



#3.list_add_tail

static inline void list_add_tail(struct list_head *new, struct list_head *head)

{

__list_add(new, head->prev, head);

}

*& 将new结构加入到head的前面,即左边,若head为头节点,则遍历会是正序的遍历



#4.

@3.实验

#1.双向循环链表头的初始化

#define NUM 10

typedef struct List_test

{

unsigned char number;

struct list_head list;

}LIST_TEST; /定义最简单的链表结构/

static LIST_TEST List_table[NUM];

unsigned char i = 0;

LIST_TEST* pos;

for(i = 1;i < NUM;i++)

{

List_table[i].number = i;

}

/1.初始 化,链表头next,prev均指向自己/

NIT_LIST_HEAD(&(List_table[i].list));

#2.链表的连接

/2.将链表通过next,prev指针连接起来/

/list_add_tail:将new加到参数的左边/

/参数是头节点,正序排列/

/参数是尾节点,逆序排列/

for(i = 1;i < NUM;i++)

{

list_add_tail(&(List_table[i].list),&(List_table[0].list));

}

#3.遍历并输出

/3.遍历整个链表/

i = 0;

list_for_each_entry(pos,&(List_table[0].list),list)

{

i++;

printf(“List_table[%d] = %d “,i,pos->number);

}

printf(“\r\n “);

#4.使用另外一种插入新元素的方法

//重新初始化列表头

INIT_LIST_HEAD(&(List_table[0].list));

/list_add:将new加到参数的右边/

/参数是头节点,逆序排列/

/参数是尾节点,正序排列/

for(i = 1;i < NUM;i++)

{

list_add(&(List_table[i].list),&(List_table[0].list));

}

#5.遍历并输出

i = 0;

list_for_each_entry(pos,&(List_table[0].list),list)

{

i++;

printf(“List_table[%d] = %d “,i,pos->number);

}

printf(“\r\n “);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux-list