计算 结构体某个成员相对于结构体首地址的偏移量 offsetof宏的实现

#define offsetof(s, m) (size_t)&( ((s*)0)->m )

这个宏的定义在stddef.h中定义。

分析:
  首先将0强制类型转化为结构体指针类型s*,此时的零的类型就是 s*,那么其当然可以访问其成员m(通过(s*)0 -> m 的方式访问),那么此时再取这个变量的地址,即 & ((s*)0->m),这个地址呢减去结构体的基地址就是我们要求的偏移量
  结构体的基地址是什么呢,不就是(s*)0吗?那么(s*)0等于多少?不就是零嘛(你再怎么类型转化,0就是零,只不过这个指针在加减1时其加减的字节数目不一样了而已)。关于这一点的测试,见:

#include <iostream>
using namespace std;
int main()
{
    int *p = (int*)0;
    cout << p << endl;   //输出为:0
    return 0;
}

  现在就很简单了,我们要求的偏移量等于& ((s*)0->m) - 0 = & ((s*)0->m),然后再将这个偏移量强制类型转化为size_t类型,size_t也是一个宏,就是基本数字类型,int或者long。

扩展

这个宏是很有用的,在linux内核中,有很多不同的结构通过一个list_head结构链接在一起,这些不同的结构都有一个list_head类型的成员变量(下文我们称这些不同的结构为容器),我们在访问 这些容器内的数据时,其实是通过list_head经过一定的操作来访问的,所谓的操作就是指通过list_head来找到以list_head为成员变量的 容器 的基地址。

怎么找呢?

通过offsetof找啊,offsetof能够得到list_head结构相对于其容器的偏移量,然后将list_head的地址减去这个偏移量就得到了其容器的基地址,有了这个基地址,再去访问容器内的变量就很简单了,就通过“ -> “ 操作就行了。关于内核中的list_head链表这个结构的详细介绍见:linux内核链表以及list_entry–linux内核数据结构

参考:

嵌入式高级c语言 P29

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值