先直接上程序,代码中包含了注释已经说清楚。在linux的应用层中编译、测试:
感谢李慧芹的B站课程:史上最强最细腻的linux嵌入式C语言学习教程【李慧芹老师】_哔哩哔哩_bilibili
- #include
- #include
-
-
-
-
-
- // 下面的宏来自于:
- #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-
-
- #define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
-
-
- // 下面的结构体定义来自于
- struct list_head {
- struct list_head *next;
- struct list_head *prev;
- };
-
- // 下面的宏及函数摘自于
- #define list_entry(ptr, type, member) \
- container_of(ptr, type, member)
-
-
- #define list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
-
- #define LIST_HEAD_INIT(name) { &(name), &(name) }
-
- #define LIST_HEAD(name) \
- struct list_head name = LIST_HEAD_INIT(name)
-
-
-
- void INIT_LIST_HEAD(struct list_head *list)
- {
- list->next = list;
- list->prev = list;
- }
-
- // 将 new 插入到 prev 和 next 的中间
- 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 插入到 head 的后面
- void list_add(struct list_head *new, struct list_head *head)
- {
- __list_add(new, head, head->next);
- }
-
- // 将 new 插入到 head 的前面
- void list_add_tail(struct list_head *new, struct list_head *head)
- {
- __list_add(new, head->prev, head);
- }
-
- void __list_del(struct list_head * prev, struct list_head * next)
- {
- next->prev = prev;
- prev->next = next;
- }
-
- void __list_del_entry(struct list_head *entry)
- {
- __list_del(entry->prev, entry->next);
- }
-
- //
- // 下面是业务层应用代码
- //
- // 应用层业务的结构体定义:
- struct student
- {
- int id;
- char name[128];
- int ch; //语文分数
- int ma; //数学分数
- int en; //英语分数
- struct list_head list; //包含一个 list_head
- };
-
- void print_stu(struct student *st);
-
-
- int main()
- {
- //
- // 0.1 测试宏 offsetof 使用
- //
- printf("id offset=%ld\n", offsetof(struct student, id));
- printf("name offset=%ld\n", offsetof(struct student, name));
- printf("ch offset=%ld\n", offsetof(struct student, ch));
- printf("ma offset=%ld\n", offsetof(struct student, ma));
- printf("en offset=%ld\n", offsetof(struct student, en));
- printf("list offset=%ld\n", offsetof(struct student, list));
- /*
- id offset=0
- name offset=4
- ch offset=132
- ma offset=136
- en offset=140
- list offset=144
- 上面看出,宏offsetof(TYPE, MEMBER),就是返回成员MEMBER相对首的偏移!
- */
-
-
- // 0.2 测试宏 container_of 使用
- struct student stu={100, "std100", 78, 88, 98, NULL,};
- struct student *p=container_of(&stu.list, struct student, list);
- printf("&stu=%p\n", &stu);
- printf("&stu.list=%p\n", &stu.list);
- printf("&p=%p\n", p);
- /*
- &stu= 0x7fffa2f4e1b0
- &stu.list= 0x7fffa2f4e240 0x240-0x1b0=144 即是上述list的偏移off
- &p= 0x7fffa2f4e1b0
- 上面看出,宏container_of(ptr, type, member) 即是返回结构体变量的首地址。
- 那么问题来了,为何搞这么复杂的一个转换来获取首地址呢?
- 直接使用&stu不就得到完了嘛!别急,看下面的应用!
- */
-
- int i=0;
- LIST_HEAD(head);
- //
- // 1. 创建5个结构体,使用 list 连起来
- //
- for(i=0; i<5; i++)
- {
- struct student *st=malloc(sizeof(struct student));
- sprintf(st->name, "stu%02d", i+1);
- st->id=i+1;
- st->ch=rand()%100;
- st->ma=rand()%100;
- st->en=rand()%100;
-
- printf("id=%d, name=%s, ch=%d, ma=%d, en=%d\n",
- st->id, st->name, st->ch, st->ma, st->en);
-
- list_add(&(st->list), &head); //这里每次插入到head的后面!
- }
- /*
- id=1, name=stu01, ch=83, ma=86, en=77
- id=2, name=stu02, ch=15, ma=93, en=35
- id=3, name=stu03, ch=86, ma=92, en=49
- id=4, name=stu04, ch=21, ma=62, en=27
- id=5, name=stu05, ch=90, ma=59, en=63
- 注意上述创建的原始顺序!
- */
-
- printf("\n");
-
- //
- // 2. 遍历打印
- //
- struct list_head *c;
- list_for_each(c, &head)
- {
- struct student *st=container_of(c, struct student, list);
- print_stu(st);
- }
- /*
- id=5, name=stu05, ch=90, ma=59, en=63
- id=4, name=stu04, ch=21, ma=62, en=27
- id=3, name=stu03, ch=86, ma=92, en=49
- id=2, name=stu02, ch=15, ma=93, en=35
- id=1, name=stu01, ch=83, ma=86, en=77
- 因为是每次插入到head的后面,所以链表里面的顺序是5、4、3....
- */
-
- //
- // 3. 查找一个节点
- //
- list_for_each(c, &head)
- {
- struct student *st=container_of(c, struct student, list);
- if(st->id==3)
- {
- printf("\nfind it!\n");
- print_stu(st);
- }
- }
-
- //
- // 4. 删除一个节点
- //
- list_for_each(c, &head)
- {
- struct student *st=container_of(c, struct student, list);
- if(st->id==3)
- {
- __list_del_entry(&st->list);
- free(st);
- }
- }
-
- //
- // 5. 再次输出打印
- //
- printf("\nreprintf:\n");
- list_for_each(c, &head)
- {
- struct student *st=container_of(c, struct student, list);
- print_stu(st);
- }
- }
-
-
- void print_stu(struct student *st)
- {
- printf("id=%d, name=%s, ch=%d, ma=%d, en=%d\n",
- st->id, st->name, st->ch, st->ma, st->en);
- }
-