![dbf749940a9d495bd9e55f085f004166.png](https://i-blog.csdnimg.cn/blog_migrate/46050f76ba6b479f62825af157075ff2.jpeg)
我们在开发中,有可能用到offsetof,来求结构成员在结构中的偏移量。例如下面的代码:
![60bca9929dbc5de8bdfa232f355dc1c4.png](https://i-blog.csdnimg.cn/blog_migrate/0f197166d33a226b55a52b5bd9930915.jpeg)
上面代码的功能,是使用“offsetof”的功能,查询结构体TMyStruct中三个成员m_pcName、m_sAge、m_iScore的偏移量。
offsetof是函数吗?在Linux中,使用man命令查询offsetof的帮助文档,得到的信息如下:
#include size_t offsetof(type, member);
从帮助信息来看,offsetof简直一定是函数,但是我们很惊讶,C语言函数怎么能够传入这样的参数:
(1)结构类型名;
(2)没有给出结构变量名,直接使用成员变量。
真实的答案是,确实不能给C语言函数传入这种参数。offsetof也并不是函数,只是一个宏定义:
#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)
上面的宏定义让我们有点摸不着头脑,我们可以将这个宏定义变得复杂一点,但是更容易理解一些:
#define offsetof(TYPE, MEMBER) ((size_t)
((char *)&((TYPE *)0)->MEMBER - (char *)(TYPE *)0))
如果您是STM32的程序员,深入研究过STM32如何将一批寄存器变量组装成struct结构,您就理解C语言编译器对struct的处理方式:
在C语言中,对struct的处理方式,就是将struct变量的成员,变为struct变量的地址+偏移量,然后转换为对应的类型。
因此,offsetof宏定义最巧妙的地方,是欺骗编译器,把地址零当成某个结构类型变量的地址,然后算出偏移量。
讲到这里,基本上将offsetof的巧妙之处说完了。
现在延伸一下,上面的程序中,三个成员变量的偏移值应该是0,7,9吧?实际上,您猜错了,真实的答案是0,8,12:
![c904dca8a50f8b3f93a1c43afcf5435e.png](https://i-blog.csdnimg.cn/blog_migrate/dadfe78e2ad34ba2549a8d3265429626.jpeg)
为什么是这样的结果?这里先卖个关子,下节课讲述具体原因。