zoukankan      html  css  js  c++  java
  • container_of()宏解析

            在内核中很多地方都会使用到宏container_of()。

            都知道宏container_of()的作用是:根据结构体中一个域成员变量的指针获取指向整个结构体的指针、现在来分析这个宏是如何实现的;

            内核中container_of()代码如下:

    /**
     * container_of - cast a member of a structure out to the containing structure
     * @ptr:    the pointer to the member.
     * @type:   the type of the container struct this is embedded in.
     * @member: the name of the member within the struct.
     */
    #define container_of(ptr, type, member) ({          \
    	const typeof(((type *)0)->member)*__mptr = (ptr);    \
    		     (type *)((char *)__mptr - offsetof(type, member)); })

            内核中offsetof()代码如下:

    #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
    一、理论解析

           先来说说offsetof()宏;

           1. (type *)0:将0转化为TYPE型指针;

           2. (TYPE *)0)->MEMBER:表示访问TYPE型指针0指向结构体的成员变量MEMBER;

           3. &((TYPE *)0)->MEMBER):表示取成员变量MEMBER的地址;

           4. ((size_t) :类型转化

           巧妙之处在于:将0转换成(TYPE*),然后结构体以内存空间首地址0作为起始地址,则成员地址就成为偏移地址。

           再来说说container_of()宏;

           1.  typeof(((type *)0)->member)的作用是获取成员member的结构类型;

            2. typeof(((type *)0)->member)*__mptr == (ptr);表示定义临时变量__mptr,将指针ptr赋值给__mptr;

            3. (type *)( (char *)__mptr - offsetof(type,member) )在(type *)作用下进行将字节型的结构体起始指针转换为type *型的结构体起始指针;

    二、案例解析:

            以类型struct example_st为例:

    struct example_st{
    	type_fst mem1;
    	type_sec mem2;
    	type_thd mem3;
    	type_fth mem4;
    };

             进行地址标记:


            container_of(sec, struct example_st, mem2))代入宏

    container_of(sec, struct example_st, mem2) ({          \
    	const typeof(((struct example_st *)0)->mem2)*__mptr = (sec);    \
            (struct example_st *)((char *)__mptr - offsetof(struct example_st, mem2)); })
            第三行offsetof是计算mem2在结构体struct example_st,中偏移量,等于0x0008;
            第二行可知__mptr = 0xa018;

            第三行计算结果是:0xa018 - 0x0008 = 0xa0010;

    三、程序实例

    list.h

    /**********************************************
     * Author: lewiyon@hotmail.com
     * File name: list.h
     * Description: define some macroes
     * Date: 2011-12-29
     *********************************************/
    #ifndef __LIST_H
    #define __LIST_H
    
    //typedef unsigned long size_t;
    
    #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) );})
    
    #endif

    test.c

    /**********************************************
     * Author: lewiyon@hotmail.com
     * File name: test.h
     * Description: test the macroes in the core.h 
     * Date: 2011-12-29
     *********************************************/
    
    #include <malloc.h>
    #include "list.h"
    
    struct student{
        char *name;
        char sex;
        unsigned long id;
        int age;
        int money;
    };
    
    static struct student *id_stu(unsigned long *id_no)
    {
        return (container_of(id_no, struct student, id));
    }
    
    int main(int argc, char *argv[])
    {
        unsigned long offset;
        struct student *stu, *stu_tst;
    
        stu_tst = NULL;
        stu = (struct student *)malloc(sizeof(struct student));
        stu->name = "lewiyon"; 
        stu->sex = 'M'; 
        stu->id = 2004035000; 
        stu->age = 26; 
        stu->money =0;
        printf("-------------------------------\n");
        printf("stu         = %p\n", stu);
        printf("&stu->name  = %p\n", &stu->name);
        printf("&stu->sex   = %p\n", &stu->sex);
        printf("&stu->id    = %p\n", &stu->id);
        printf("&stu->age   = %p\n", &stu->age);
        printf("&stu->money = %p\n", &stu->money);
        printf("stu->name   = %s\n", stu->name);
        printf("-------------------------------\n");
        
        stu_tst = id_stu(&stu->id);
        offset = offsetof(struct student, id);
        printf("offset          = %p\n", offset);
        printf("stu_tst         = %p\n", stu_tst);
        printf("&stu_tst->name  = %p\n", &stu_tst->name);
        printf("&stu_tst->sex   = %p\n", &stu_tst->sex);
        printf("&stu_tst->id    = %p\n", &stu_tst->id);
        printf("&stu_tst->age   = %p\n", &stu_tst->age);
        printf("&stu_tst->money = %p\n", &stu_tst->money);
        printf("stu_tst->name   = %s\n", stu_tst->name);
    
        return 0;
    }

  • 相关阅读:
    离线安装MySQL5.7
    ELK应用之一:ELK平台搭建部署
    RabbitMQ的安装部署
    Docker应用五:使用Dockerfile部署MongoDB
    Zabbix应用八:Zabbix监控MongoDB
    Zabbix应用七:Zabbix发送短信报警
    Zabbix应用六:Zabbix监控Redis
    Zabbix应用五:Zabbix监控多Tomcat
    python序列(列表和元祖)
    wps实现自动编码
  • 原文地址:https://www.cnblogs.com/youngerchina/p/5624638.html
Copyright © 2011-2022 走看看