zoukankan      html  css  js  c++  java
  • offsetof与container_of宏[总结]

    转载自:https://www.cnblogs.com/Anker/p/3472271.html

    1、前言

      今天在看代码时,遇到offsetof和container_of两个宏,觉得很有意思,功能很强大。offsetof是用来判断结构体中成员的偏移位置,container_of宏用来根据成员的地址来获取结构体的地址。两个宏设计的很巧妙,值得学习。linux内核中有着两个宏的定义,并在链表结构中得到应用。不得不提一下linux内核中的链表,设计的如此之妙,只需要两个指针就搞定了。后续认真研究一下这个链表结构。

    2、offsetof宏

      使用offsetof宏需要包含stddef.h头文件,实例可以参考:http://www.cplusplus.com/reference/cstddef/offsetof/

          offsetof宏的定义如下:

    #define offsetof(type, member) (size_t)&(((type*)0)->member)

      巧妙之处在于将地址0强制转换为type类型的指针,从而定位到member在结构体中偏移位置。编译器认为0是一个有效的地址,从而认为0是type指针的起始地址。

    3、container_of宏

      使用container_of宏需要包含linux/kernel.h头文件,container_of宏的定义如下所示:

    #define container_of(ptr, type, member) ({ 
         const typeof( ((type *)0)->member ) *__mptr = (ptr); 
         (type *)( (char *)__mptr - offsetof(type,member) );})    

    container_of宏分为两部分,

    第一部分:const typeof( ((type *)0)->member ) *__mptr = (ptr);

    通过typeof定义一个member指针类型的指针变量__mptr,(即__mptr是指向member类型的指针),并将__mptr赋值为ptr。

    第二部分: (type *)( (char *)__mptr - offsetof(type,member) ),通过offsetof宏计算出member在type中的偏移,然后用member的实际地址__mptr减去偏移,得到type的起始地址,即指向type类型的指针。

    第一部分的目的为了利用了编译器的类型检查机制做了一份校验工作,即如果传入的ptr类型和type->member的类型不匹配,会报错。

    如果单纯为了得到地址只需要(char *)ptr-&((type* 0)->member),转换为(char*)的目的为offsetof宏最后得到的是整数,不转换为char *的话,正常指针加减

    是按变量类型所占的字节数来移动的,会导致错误。

    4、测试程序

    复制代码
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 #define NAME_STR_LEN  32
     5 
     6 #define offsetof(type, member) (size_t)&(((type*)0)->member)
     7 
     8 #define container_of(ptr, type, member) ({ 
     9         const typeof( ((type *)0)->member ) *__mptr = (ptr); 
    10         (type *)( (char *)__mptr - offsetof(type,member) );})
    11 
    12 typedef struct student_info
    13 {
    14     int  id;
    15     char name[NAME_STR_LEN];
    16     int  age;
    17 }student_info;
    18 
    19 
    20 int main()
    21 {
    22     size_t off_set = 0;
    23     off_set = offsetof(student_info, id);
    24     printf("id offset: %u
    ",off_set);
    25     off_set = offsetof(student_info, name);
    26     printf("name offset: %u
    ",off_set);
    27     off_set = offsetof(student_info, age);
    28     printf("age offset: %u
    ",off_set);
    29     student_info *stu = (student_info *)malloc(sizeof(student_info));
    30     stu->age = 10;
    31     student_info *ptr = container_of(&(stu->age), student_info, age);
    32     printf("age:%d
    ", ptr->age);
    33     printf("stu address:%p
    ", stu);
    34     printf("ptr address:%p
    ", ptr);
    35     return 0;
    36 }
    复制代码

    测试结果:

    5、参考网址

    http://blog.csdn.net/thomas_nuaa/article/details/3542572

    http://blog.chinaunix.net/uid-28489159-id-3549971.html

    http://blog.csdn.net/yinkaizhong/article/details/4093795

    转载自:https://www.cnblogs.com/Anker/p/3472271.html
  • 相关阅读:
    eclipse下c/cpp " undefined reference to " or "launch failed binary not found"问题
    blockdev 设置文件预读大小
    宝宝语录
    CentOS修改主机名(hostname)
    subprocess报No such file or directory
    用ldap方式访问AD域的的错误解释
    英特尔的VTd技术是什么?
    This virtual machine requires the VMware keyboard support driver which is not installed
    Linux内核的文件预读详细详解
    UNP总结 Chapter 26~29 线程、IP选项、原始套接字、数据链路访问
  • 原文地址:https://www.cnblogs.com/FREMONT/p/9824880.html
Copyright © 2011-2022 走看看