linun内核中常用的两个宏定义
#ifndef offsetof
#define offsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)
#endif
offsetof用于计算TYPE结构体中MEMBER成员的偏移位置。首先0强制转换为TYPE型指针,MEMBER为一个成员,0地址处是留给操作系统使用的,所以0地址处没有TYPE类型结构体,所以会奔溃么? 编译器清楚的知道结构体成员变量的偏移位置,通过结构体变量首地址与偏移量定位成员变量。
#include <stdio.h>
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER)
//编译器不会访问0地址处的结构体变量(不存在),而是用0加MEMBER的偏移,得到一个地址,偏移量后又转换成无符号int类型,得到MEMBER偏移量,就像下边pst换为0的意思
#endifstruct ST
{
int i; // 0偏移
int j; // 4
char c; // 8
};
void func(struct ST* pst)
{
int* pi = &(pst->i); // 0 (unsigned int)pst+0
int* pj = &(pst->j); // 4 (unsigned int)pst+4
char* pc = &(pst->c); // 8 (unsigned int)pst+8
printf("pst = %p\n", pst); //编译器没有真正访问pst所指向的内容,而是首地址加偏移量
printf("pi = %p\n", pi);
printf("pj = %p\n", pj);
printf("pc = %p\n", pc);
}
int main()
{
struct ST s = {0};
func(&s);
func(NULL); //000000000 000000000 000000004 00000008
printf("offset i: %d\n", offsetof(struct ST, i));//st结构体中i的偏移量
printf("offset j: %d\n", offsetof(struct ST, j));
printf("offset c: %d\n", offsetof(struct ST, c));
return 0;
}
第二个宏:
ifndef container_of
#define container_of(ptr,type,member) ({
const typeof(((type*)0)->member)* _mptr=(ptr);
(type*)((char*)_mptr-offsetof(type,member));})
#endif
({})是什么?
({})是GNU C编译器的语法扩展,与逗号表达式类似,结果为最后一个语句的值。
int a=0;
int b=0;
int r=(a=1,b=2,a+b); <==>int r=({int a=1,int b=2;a+b;});
typeof是一个关键字吗?
typeof 是GNU C编译器的特有关键字
typeof只在编译器生效,用于得到变量的类型
int i=100;
typeof(i) j=i; //=>int j=i;
const typeof(i)* p=&j; //const int* p=&j;
最后原理:
数学关系:pc=p+offset
size_t offset=offsetof(struct ST,c);//得到c在struct ST中的偏移量
struct ST* p=(struct ST*)((char*)pc-offset);//pc强制类型转换为char* 做指针运算
#include <stdio.h>
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER)
#endif
#ifndef container_of#define container_of(ptr, type, member) ({ \
const typeof(((type*)0)->member)* __mptr = (ptr); \
(type*)((char*)__mptr - offsetof(type, member)); })
#endif
//结果为最后一个语句的结果,先求member在type中的偏移量,然后用meptr也就是ptr减去偏移量,得到结构体的首地址。逗号之前的语句起类型检查的作用,container_of只可以用宏来实现,宏由预处理器处理,做的是单纯的文本替换,不会进行类型检查,有可能出现错误,如误用pe一样,那就只是两行语句,指针定义不能放在逗号表达式中,就使用了({}),要得到member的类型,使用typeof通过变量得到类型,将0地址转换为type类型的结构体指针,通过指针访问member,为什么访问0地址没奔溃?typeof是在编译期有用的,在编译期间就能拿到member的类型了,不用等到运行期,在运行时 typeof(((type*)0)->member)已经成为了类型。
#ifndef container_of_new#define container_of_new(ptr, type, member) ((type*)((char*)(ptr) - offsetof(type, member)))
#endif
//改写
struct ST
{
int i; // 0
int j; // 4
char c; // 8
};
void method_1()
{
int a = 0;
int b = 0;
int r = (
a = 1,
b = 2,
a + b
);
printf("r = %d\n", r);
}
void method_2()
{
int r = ( {
int a = 1;
int b = 2;
a + b;
} );
printf("r = %d\n", r);
}
void type_of()
{
int i = 100;
typeof(i) j = i;
const typeof(j)* p = &j;
printf("sizeof(j) = %d\n", sizeof(j));
printf("j = %d\n", j);
printf("*p = %d\n", *p);
}
int main()
{
// method_1(); //r=3
// method_2(); //r=3
// type_of(); //sizeof<j>=4 j=100 *p=100
struct ST s = {0};
char* pc = &s.c;
int e = 0;
int* pe = &e; //pc换为pe的话第二个简写就有错了
struct ST* pst = container_of(pc, struct ST, c);
printf("&s = %p\n", &s);
printf("pst = %p\n", pst);//打印值一样
return 0;
}
编译器清楚的知道结构体成员变量的偏移位置,在编译时就知道,通过0地址得到具体的偏移位置。({})与逗号表达式类似,结果为最后一个语句的值,type只在编译器生效,用于得到变量的类型。container_of使用({})进行类型安全检查。
32、linux内核链表
移植linux内核链表,使其适用于非GNU编译器,分析基本实现
移植注意事项:清除文件间的依赖,剥离依赖文件中与链表实现相关的代码,
清除平台相关代码(GNU C) ,({}),typeof,_builtin_prefetch(提高访问效率),static inline
linux内核链表的实现:带头结点的双向循环链表,且头结点为表中成员,头结点的next指针指向首结点,头结点的prev指针指向尾节点。
linux内核链表的结点定义:
struct list_head
{
struct list_head *next,*prev;
}; //数据放在那里?由使用的人自定义
使用struct list_head自定义链表结点
struct Node{}
struct list_head head;
Type1 value1;
Type2 value2;
linux内核链表的创建及初始化
struct Node{
struct list_head head;
int value;};
int main(void){
struct Node1={0};
struct list_head* list=(struct list_head*)&l;
INIT_LIST_HEAD(list);
}
linux内核链表的插入操作:
在链表头部插入:list_add(new,head)
在链表尾部插入:list_add_tail(new,head)
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
// #include <linux/types.h>//依赖
// #include <linux/stddef.h>
// #include <linux/poison.h>
// #include <linux/prefetch.h>
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif // #include <linux/stddef.h>
#ifndef container_of
#define container_of(ptr, type, member) ((type *)((char *)ptr - offsetof(type,member)))
#endif
#define prefetch(x) ((void)x)
#define LIST_POISON1 (NULL)
#define LIST_POISON2 (NULL)
struct list_head {
struct list_head *next, *prev;
};
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
#ifndef CONFIG_DEBUG_LIST
static 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;
}
#else
extern void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next);
#endif
static void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
#ifndef CONFIG_DEBUG_LIST
static void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
static void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1; //变成空
entry->prev = LIST_POISON2;
}
#else
extern void __list_del_entry(struct list_head *entry);
extern void list_del(struct list_head *entry);
#endif
static void list_replace(struct list_head *old,
struct list_head *new)
{
new->next = old->next;
new->next->prev = new;
new->prev = old->prev;
new->prev->next = new;
}
static void list_replace_init(struct list_head *old,
struct list_head *new)
{
list_replace(old, new);
INIT_LIST_HEAD(old);
}
static void list_del_init(struct list_head *entry)
{
__list_del_entry(entry);
INIT_LIST_HEAD(entry);
}
static void list_move(struct list_head *list, struct list_head *head)
{
__list_del_entry(list);
list_add(list, head);
}
static void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del_entry(list);
list_add_tail(list, head);
}
static int list_is_last(const struct list_head *list,
const struct list_head *head)
{
return list->next == head;
}
static int list_empty(const struct list_head *head)
{
return head->next == head;
}
static int list_empty_careful(const struct list_head *head)
{
struct list_head *next = head->next;
return (next == head) && (next == head->prev);
}
static void list_rotate_left(struct list_head *head)
{
struct list_head *first;
if (!list_empty(head)) {
first = head->next;
list_move_tail(first, head);
}
}
static int list_is_singular(const struct list_head *head)
{
return !list_empty(head) && (head->next == head->prev);
}
static void __list_cut_position(struct list_head *list,
struct list_head *head, struct list_head *entry)
{
struct list_head *new_first = entry->next;
list->next = head->next;
list->next->prev = list;
list->prev = entry;
entry->next = list;
head->next = new_first;
new_first->prev = head;
}
static void list_cut_position(struct list_head *list,
struct list_head *head, struct list_head *entry)
{
if (list_empty(head))
return;
if (list_is_singular(head) &&
(head->next != entry && head != entry))
return;
if (entry == head)
INIT_LIST_HEAD(list);
else
__list_cut_position(list, head, entry);
}
static void __list_splice(const struct list_head *list,
struct list_head *prev,
struct list_head *next)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
first->prev = prev;
prev->next = first;
last->next = next;
next->prev = last;
}
static void list_splice(const struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head, head->next);
}
static void list_splice_tail(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head->prev, head);
}
static void list_splice_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head, head->next);
INIT_LIST_HEAD(list);
}
}
static void list_splice_tail_init(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head->prev, head);
INIT_LIST_HEAD(list);
}
}
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
pos = pos->next)
#define __list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_prev(pos, head) \
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
pos = pos->prev)
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#define list_for_each_prev_safe(pos, n, head) \
for (pos = (head)->prev, n = pos->prev; \
prefetch(pos->prev), pos != (head); \
pos = n, n = pos->prev)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
prefetch(pos->member.prev), &pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
#define list_prepare_entry(pos, head, member) \
((pos) ? : list_entry(head, typeof(*pos), member))
#define list_for_each_entry_continue(pos, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_continue_reverse(pos, head, member) \
for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
prefetch(pos->member.prev), &pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
#define list_for_each_entry_from(pos, head, member) \
for (; prefetch(pos->member.next), &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_safe_continue(pos, n, head, member) \
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_safe_from(pos, n, head, member) \
for (n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
n = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
#define list_safe_reset_next(pos, n, member) \
n = list_entry(pos->member.next, typeof(*pos), member)
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
static void INIT_HLIST_NODE(struct hlist_node *h)
{
h->next = NULL;
h->pprev = NULL;
}
static int hlist_unhashed(const struct hlist_node *h)
{
return !h->pprev;
}
static int hlist_empty(const struct hlist_head *h)
{
return !h->first;
}
static void __hlist_del(struct hlist_node *n)
{
struct hlist_node *next = n->next;
struct hlist_node **pprev = n->pprev;
*pprev = next;
if (next)
next->pprev = pprev;
}
static void hlist_del(struct hlist_node *n)
{
__hlist_del(n);
n->next = LIST_POISON1;
n->pprev = LIST_POISON2;
}
static void hlist_del_init(struct hlist_node *n)
{
if (!hlist_unhashed(n)) {
__hlist_del(n);
INIT_HLIST_NODE(n);
}
}
static void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}
/* next must be != NULL */
static void hlist_add_before(struct hlist_node *n,
struct hlist_node *next)
{
n->pprev = next->pprev;
n->next = next;
next->pprev = &n->next;
*(n->pprev) = n;
}
static void hlist_add_after(struct hlist_node *n,
struct hlist_node *next)
{
next->next = n->next;
n->next = next;
next->pprev = &n->next;
if(next->next)
next->next->pprev = &next->next;
}
static void hlist_add_fake(struct hlist_node *n)
{
n->pprev = &n->next;
}
static void hlist_move_list(struct hlist_head *old,
struct hlist_head *new)
{
new->first = old->first;
if (new->first)
new->first->pprev = &new->first;
old->first = NULL;
}
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
#define hlist_for_each(pos, head) \
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
pos = pos->next)
#define hlist_for_each_safe(pos, n, head) \
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
pos = n)
#define hlist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->first; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
#define hlist_for_each_entry_continue(tpos, pos, member) \
for (pos = (pos)->next; \
pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
#define hlist_for_each_entry_from(tpos, pos, member) \
for (; pos && ({ prefetch(pos->next); 1;}) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = pos->next)
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->first; \
pos && ({ n = pos->next; 1; }) && \
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = n)
#endif
#include <stdio.h>
#include "LinuxList.h"
void list_demo_1()
{
struct Node
{
struct list_head head;
int value;
};
struct Node l = {0};
struct list_head* list = (struct list_head*)&l;
struct list_head* slider = NULL;
int i = 0;
INIT_LIST_HEAD(list); //首尾都指向自己,
for(i=0; i<5; i++) //插入元素
{
struct Node* n = (struct Node*)malloc(sizeof(struct Node));
n->value = i;
list_add_tail((struct list_head*)n, list);
}
list_for_each(slider, list)
{
printf("%d\n", ((struct Node*)slider)->value);
}
list_for_each(slider, list)
{
if( ((struct Node*)slider)->value == 3 )
{
list_del(slider);
free(slider);
break;
}
}
list_for_each(slider, list)
{
printf("%d\n", ((struct Node*)slider)->value);
}
printf("Delete end ...\n");
}
void list_demo_2() //数值和链表交换顺序
{
struct Node
{
int value;
struct list_head head;
};
struct Node l = {0};
struct list_head* list = &l.head; //数据和指针改变位置之前struct list_head* list = (struct list_head*)&l;
struct list_head* slider = NULL;
int i = 0;
INIT_LIST_HEAD(list);
printf("Insert begin ...\n");
for(i=0; i<5; i++)
{
struct Node* n = (struct Node*)malloc(sizeof(struct Node));
n->value = i;
list_add(&n->head, list);
//不能是之前的list_add((struct list_head*)n,list),因为这个时候head放在尾部
}list_for_each(slider, list)
{
printf("%d\n", list_entry(slider, struct Node, head)->value);
//不能是之前的,list_entry就是contained_of。slider指向Node里的head成员,返回首地址
}printf("Insert end ...\n");
printf("Delete begin ...\n");
list_for_each(slider, list)
{
struct Node* n = list_entry(slider, struct Node, head);
//不能写成(struct Node*)slider)->value == 3,此时slider的起始地址与Node类型不一样
if( n->value == 3 ){
list_del(slider);
free(n); //不用slider直接free,临时变量n,异常安全
break;
}
}
list_for_each(slider, list)
{
printf("%d\n", list_entry(slider, struct Node, head)->value);
}printf("Delete end ...\n");
}
int main()
{
// list_demo_1();
// list_demo_2();
return 0;
}
将struct list_head作为结点结构体的第一个成员或最后一个成员,struct list_head作为最后一个成员时,需要使用list_entry宏,list_entry的定义中使用了container_of宏。