• 正文
    • 开门见山
    • 实际应用
  • 相关推荐
申请入驻 产业图谱

【LeafC】C语言之宏魔法4:offsetof&container_of

02/10 22:50
536
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

开门见山

offsetof用于获取结构体成员的相对偏移,container_of通过结构体字段获取结构体地址。

offsetof

offsetof的标准实现如下,其被定义在stddef.h中:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

offsetof宏的计算发生在编译阶段。

GCC编译器还为此提供一个内置函数__builtin_offsetof以提高编译效率:

#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)

container_of

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

typeofGCC编译器的一个扩展,用于获取变量或表达式的类型。在container_of宏中,typeof( ((type *)0)->member )用于获取结构体type中成员member的类型。

Linux内核实现中,为了更严格的类型检查,和更好的符合C语言标准,container_of宏的实现如下:

#define container_of(ptr, type, member) ({    
 void *__mptr = (void *)(ptr);     
 static_assert(__same_type(*(ptr), ((type *)0)->member) || 
        __same_type(*(ptr), void),   
        "pointer type mismatch in container_of()"); 
 ((type *)(__mptr - offsetof(type, member))); })

static_assertC11引入的静态断言机制,__same_typeGCC编译器提供的内置函数实现。

实际应用

container_of典型的应用就是Linux内核中链表的实现:

struct list_head {
 struct list_head *next, *prev;
};
#define list_entry(ptr, type, member) 
 container_of(ptr, type, member)

// 通过链表节点获取节点所在结构,以下为示意,省略部分代码
struct my_struct {
    int a;
    char b;
    struct list_head node;
};
struct my_struct data;
struct my_struct *entry = list_entry(&data, struct my_struct, node)
点赞
收藏
评论
分享
加入交流群
举报

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录