实际应用地址偏移实现结构体成员访问

#include <stdio.h>
#define OFFSET(Type,member) (size_t)&(((Type*)0)->member)
typedef struct goods{
 int num;
 int stock;
 int price;
 int vol;
}goods;
int FindnOutput(size_t offset, goods *h, int n,int S){
 int f = 0;
 for (int i = 0;i < n; i++)
 {
  int temp = *(int*)((size_t)(h+i) + offset);
  if (temp >= S)
  {
   printf("%d %d %d %d",(h+i)->num,(h+i)->stock, (h+i)->price,(h+i)->vol);
   f = 1;
  }
 }
 if (!f)
 {
  printf("nothing");
 }
 return 0;
}


int main()
{
 int n;
 int K,S;
 size_t offset;
 goods G[1001];
 scanf("%d",&n);
 for (int i = 0; i < n; i++)
 {
  scanf("%d%d%d%d",&G[i].num,&G[i].stock,&G[i].price,&G[i].vol);
 }
 scanf("%d%d",&K,&S);
 switch (K)
 {
 case 1:
  offset = OFFSET(goods,stock);
  FindnOutput(offset,G,n,S);
  break;
 case 2:
  offset = OFFSET(goods,price);
  FindnOutput(offset,G,n,S);
  break;
 case 3:
  offset = OFFSET(goods,vol);
  FindnOutput(offset,G,n,S);
  break;
 }
 return 0;
}
以前随手写的,这是一个大一经常碰到的结构体学习的基础问题:有一种货物,用结构体来描述它,goods为货物结构,它有成员
 int num;
 int stock;
 int price;
 int vol;
进货量,库存,价格,体积

现在有一个需求,给定一个数S,我需要根据上面4个成员的情况,输出货物某个成员大于S的所有货物信息。比如我这次要输出所有价格大于10的货物,下次可能变成我要输出所有体积大于10的货物。

现在的问题是我想就设置一个函数,可以根据输入比较多种成员,减少代码量。这次比较num下次比较stock,仅仅需要调用一个函数,那这要怎么实现?


我上面的办法是用偏移量,(内核之类的经常这样使用,不过晦涩难懂)。

#define OFFSET(Type,member) (size_t)&(((Type*)0)->member)
这个宏,是:

复制点东西过来给lz参考,
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
先分析一下这个 宏的运行机理:
一共4步
1. ( (TYPE *)0 ) 将零转型为TYPE类型指针;
2. ((TYPE *)0)->MEMBER 访问结构中的数据成员;
3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址;
4.(size_t)(&(((TYPE*)0)->MEMBER))结果转换类型。巧妙之处在于将0转 换成(TYPE*),结构以内存空间首地址0作为起始地址,则成员地址自然为偏移地址;


“3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址;”
补充一下:
这个实现相当于获取到了 MEMBER 成员相对于其所在结构体的偏移,也就是其在对应结构体中的什么位置。


上面这两段话引用自http://bbs.chinaunix.net/thread-1917123-1-1.html

  int temp = *(int*)((size_t)(h+i) + offset);
h为goods*类型,指针类型本质上是地址 也就是一个32位/64位数字,unsigned int or size_t【这种理解有失偏颇,请参考下面的链接】

http://book.2cto.com/201402/40243.html

加上offset之后就是此成员的地址了,接着*(int *)取出该成员的值。假如此成员类型为char 那就是*(char*).



不知道还有没有其他较简单的方法。

重载?==>之后再研究一下

如果可以再更新此文。

我也不知道我上面这种方法是否是最简易的,请各位提出见解。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值