5、结构元素偏移及寻址细节的一些思考

本文深入探讨了C语言中结构体的指针偏移和宏定义的运用,通过实例展示了如何计算结构元素的偏移量,并解释了不同数据类型之间的对齐规则。此外,还介绍了结构体寻址的应用及如何从已知元素地址反推结构基址,为理解C语言底层提供了实用视角。

c语言的结构比较好玩,它的指针偏移特别有意思。

下面的宏定义也很奇怪:

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

开始我以为这个不会通过编译,因为当时我对(void *0比较敏感,就是NULL指针咯。不过这个宏定义确实是正确的。它用于计算结构元素的偏移量(字节数)。试试就知道了。

struct test

{

 char a;

 int b ;

char c;

};

 

测试语句如下:

printf("sizeof(struct test) = %d, offsetof(struct test, a) = %d, offsetof(struct test, b) = %d, offsetof(struct test, c) = %d\n", sizeof(struct test), offsetof(struct test, a), offsetof(struct test, b), offsetof(struct test, c));

 

运行结果如下:

  sizeof(struct test) = 12, offsetof(struct test, a) = 0, offsetof(struct test, b) = 4, offsetof(struct test, c) = 8

 

1、  把上面的结构稍微改一下,测试语句不变。

struct test

{

 char a;

 char  b ;

  int c;

};

 

运行结果如下:

sizeof(struct test) = 8, offsetof(struct test, a) = 0, offsetof(struct test, b) = 1, offsetof(struct test, c) = 4

 

struct test

{

 char a;

 char  b ;

 short c;

};

 

运行结果:

sizeof(struct test) = 4, offsetof(struct test, a) = 0, offsetof(struct test, b) = 1, offsetof(struct test, c) = 2

 

还好啦,我自己知道为什么会这样,可是说不上来。简单的讲吧,不同类型之间会出现4字节对齐。也不知道讲的对不对。

 

以前看到STarm结构封装,我很困惑。

typedef struct

{

  vu16 CR1;

  u16  RESERVED0;

  vu16 CR2;

  u16  RESERVED1;

  vu16 SMCR;

  u16  RESERVED2;

  vu16 DIER;

  u16  RESERVED3;

  vu16 SR;

  u16  RESERVED4;

  vu16 EGR;

  u16  RESERVED5;

  vu16 CCMR1;

  u16  RESERVED6;

  vu16 CCMR2;

  u16  RESERVED7;

  vu16 CCER;

  u16  RESERVED8;

  vu16 CNT;

  u16  RESERVED9;

  vu16 PSC;

  u16  RESERVED10;

  vu16 ARR;

  u16  RESERVED11;

  vu16 RCR;

  u16  RESERVED12;

  vu16 CCR1;

  u16  RESERVED13;

  vu16 CCR2;

  u16  RESERVED14;

  vu16 CCR3;

  u16  RESERVED15;

  vu16 CCR4;

  u16  RESERVED16;

  vu16 BDTR;

  u16  RESERVED17;

  vu16 DCR;

  u16  RESERVED18;

  vu16 DMAR;

  u16  RESERVED19;

} TIM_TypeDef;

 

#define PERIPH_BASE           ((u32)0x40000000)

#define TIM2_BASE             (APB1PERIPH_BASE + 0x0000)

 

#define TIM2                ((TIM_TypeDef *) TIM2_BASE)

 

这个也算是结构寻址的一个应用吧,使用起来还是很方便的。

 

2、  如果知道结构里某个元素的地址,这样就可以反推出结构的基址。 这是一个很有用的特性。

 struct test

{

 char a;

 char  b ;

  int c;

 list  d

};

如果list是一个双向链表,那么可以就很容易得到节点的地址,从来反推出结构的基址。不少操作系统的调度就是利用了这个原理。

 

#definelist_entry(node,type,member)    ((type *)((unsigned int)(node) - (unsigned int)(&((type *)0)->member)))

 

总结:我知道的就这么多了。 水平不咋滴,多多学习。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值