| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1179 人关注过本帖
标题:这个宏定义的理解
只看楼主 加入收藏
ml232528
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:5
帖 子:367
专家分:879
注 册:2007-7-23
结帖率:80%
收藏
 问题点数:0 回复次数:7 
这个宏定义的理解
#define offset(s,m) (size_t)&(((s*)0)->m)
这个怎么理解
实例中s是一个类 m是s的一个成员 它指向s
搜索更多相关主题的帖子: 定义 
2008-09-14 21:09
ml232528
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:5
帖 子:367
专家分:879
注 册:2007-7-23
收藏
得分:0 
#define set(s,m) (size_t)&(((s*)0)->m)
class a
{
   a* pNext;
   void* pDate;
}
int main()
{
   .
   .
   size_t m=set(a,pNext);
   .
   .
}

-︻┻┳═一 ☆ 悲伤的代价就是让自己明白什么是最重要的和应该珍惜的
2008-09-14 21:31
snakealpha
Rank: 1
来 自:扬州
等 级:新手上路
威 望:1
帖 子:267
专家分:0
注 册:2005-11-5
收藏
得分:0 
set是一个带参数的宏,表示将代码中出现set(s,m)的地方均替换为(size_t)&(((s*)0)->m),其中s,m可以使用你需要的数值。和函数有点像。
就我自己而言,一直以为参数宏是和内联函数一样的东西。不过内联函数的灵活性似乎要更强一些。

天涯也有江南信
梅破知春近
夜阑风细得香迟
不道晓来开遍向南枝
2008-09-14 21:38
StarWing83
Rank: 8Rank: 8
来 自:仙女座大星云
等 级:贵宾
威 望:19
帖 子:3951
专家分:748
注 册:2007-11-16
收藏
得分:0 
LS等于没有回答。

先看看一个类的结构,假设类的定义是:
struct s
{
    int i1,i2;
    char c1,c2;
}*pt,s1;
那么它在内存中的放置位置如下:

  V 这里是pt指向的地方。
  ------------------------>内存地址顺次增加
s:|xxxx|xxxx|x|x|....
  ^    ^    ^ ^
  i1   i2   c1 c2

假设我们要访问i1,实际上的代码是:pt->i1,它在内部的表示是*(int*)((char*)pt+0),也就是根据pt得到一个偏移量,将那个地方的一个int取出来。
如果访问s1的i1,写法是:s1.i1,实际的行为是:*(int*)((char*)&s1+0)
以此类推,假设要访问的是c1,写法和相应真实的操作为:
pt->c1           *(char*)((char*)pt+8)
s1.c1            *(char*)((char*)&s1+8)

为什么要先转化为char*呢?因为char*指针是以一个字节为单位前进的,我们只是利用这个特点而已,和char没有什么特别的关系。

好,我们回来看那个宏:
#define offset(s,m) (size_t)&(((s*)0)->m)
假设写成offset(struct s,c1),那么展开了就是:
(size_t)&(((struct s*)0)->c1)
根据我们刚才的写法,这实际上是:
(size_t)&(*((char*)(0)+8))
最外层的&和*抵消掉了,我们加一点儿空格,可以看得更清晰些:
(size_t) ( ((char*)0 + 8) )
所有的类型转换都没有改变值,我们可以继续化简:
(size_t)(0+8) 最后等于8。
这个数字就是c1在结构体s中的相对位置。

明白了么?

专心编程………
飞燕算法初级群:3996098
我的Blog
2008-09-14 21:55
ml232528
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:5
帖 子:367
专家分:879
注 册:2007-7-23
收藏
得分:0 
太谢谢楼上的了

大体上明白了
(size_t)&(((s*)0)->m) 就是求 成员m的地址与s类对象首地址的差

-︻┻┳═一 ☆ 悲伤的代价就是让自己明白什么是最重要的和应该珍惜的
2008-09-15 09:03
palmer77
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2008-9-30
收藏
得分:0 
楼上说的很细致,但粗略来说也可这样理解
(s*)0
就是将NULL指针强制转换为S型指针类型,这样编译器就知道了每个S类型对象内部的各个成员的存储情况,然后用
&(((S*)NULL)->m)
就取得了m成员相对于NULL指针的偏移地址,因为NULL指针地址为0,因此这个值就是m的相对于对象地址的偏移值
再用(size_t)解决一下int型在各个平台的长度不一致问题

[[it] 本帖最后由 palmer77 于 2008-9-30 16:08 编辑 [/it]]
2008-09-30 16:03
HAN2008
Rank: 1
等 级:新手上路
帖 子:52
专家分:0
注 册:2008-9-21
收藏
得分:0 
路过 我打酱油
2008-09-30 22:30
dicky3651
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-9-27
收藏
得分:0 
就因为4楼,我潜水很久没上线的都不得不顶!

又要学LINUX内核,又要学SDK,仲要本本书都砖头咁厚,简直是拿我的命
2010-02-23 06:56
快速回复:这个宏定义的理解
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.026319 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved