31、linux两个宏

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的意思

#endif
struct 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宏。

猜你喜欢

转载自blog.csdn.net/WS857707645/article/details/80446956