获取结构体成员偏移量的方法

个人博客

所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 nixgnauhcuy’s blog

如需转载,请标明出处!

不要站着调试程序,那会使得你的耐心减半,你需要的是全神贯注。—— Dave Storer

前言

记录工作中学习到的知识,在这里做些笔记,方便自己后面经常温习。


正文

为什么要获取结构体成员变量的偏移

我在做嵌入式工作时,在已知要获取信息的 flash 地址时,需要取出相对应的信息元素,这个时候时常需要知道结构体相对于已知地址的偏移,方便快捷的从 flash 中取出信息元素,所以时常使用这个方式。


方法

我们先用普通的方法获取结构体偏移,代码如下:

#include <stdio.h>

typedef struct {
    int a;
    int b;
    int c;
}x_t;

void test(void)
{
    x_t p;
    printf("p_addr=%d\r\n", (int)&p);
    printf("p.a_addr=%d\r\n", (int)&p.a);
    printf("p.b_addr=%d\r\n", (int)&p.b);
    printf("p.c_addr=%d\r\n", (int)&p.c);

    printf("a_offset=%d\r\n", (int)&(p.a)-(int)&p);
    printf("b_offset=%d\r\n", (int)&(p.b)-(int)&p);
    printf("c_offset=%d\r\n", (int)&(p.c)-(int)&p);
}

int main(void)
{
    test();    
    return 0;
}

输出结果:

可以看出,如果要获取结构体成员变量相对于结构体的偏移,则需要先获取结构体地址,再获取成员变量地址,成员变量地址减去结构体地址,才能获取相应的偏移。

我们再用另一种方式获取结构体偏移,代码如下:

#include <stdio.h>

typedef struct {
	int a;
	int b;
	int c;
}x_t;

void test1(void)
{
	x_t * p = 0;
	printf("a_offset = %d\n", (int)(&(p->a)));
	printf("b_offset = %d\n", (int)(&(p->b)));
	printf("c_offset = %d\n", (int)(&(p->c)));
}


int main(void)
{
	test1();
	return 0;
}

输出结果:

这里先把结构体地址指向地址 0x00000000,这时候获取成员变量相对于结构体的偏移就轻松多了,减少了一步操作,减少了计算量。


linux 内核代码求结构体成员变量偏移的方法

在内核代码 ./include/linux/stddef.h 文件中有如下定义:

#ifndef __CHECKER__
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

我们参考代码编写后:

#include <stdio.h>

typedef struct
{
	int a;
	int b;
	int c;
}x_t;


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

void test2()
{
	printf("a_offset = %d\n", (int)&((x_t*)0)->a);
	printf("b_offset = %d\n", (int)&((x_t*)0)->b);
	printf("c_offset = %d\n", (int)&((x_t*)0)->c);
}

void test3()
{
	printf("a_offset = %d\n", offsetof(x_t, a));
	printf("b_offset = %d\n", offsetof(x_t, b));
	printf("c_offset = %d\n", offsetof(x_t, c));
}

int main(void)
{
	printf("test2():\r\n");
	test2();
	printf("test3():\r\n");
	test3();
	return 0;
}

输出结果:

test2 和 test3 与上边的 test1 方法其实是一样的,宏定义中的 (TYPE*) 0 是一个空指针,如果使用空指针访问成员肯定造成段错误,但是前面的 “&” 这个符号,表示我们仅仅取 MEMBER 字段的地址,而不是引用该字段内容,因此不会造成段错误。通过将结构体地址指向 0x0 来获得结构体成员变量相对结构体地址,即方便我们使用,也方便理解。


结尾

正如前言说的,记录工作中积累的点滴经验,怕自己因为少用忘了,在这里做个记录,方便回顾。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值