CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C语言

求解:sun的一道笔试题,thanks:)

楼主lihui4003()2006-04-04 13:30:38 在 C/C++ / C语言 提问

写一个带参数宏get_struct_addr_from_member_addr(p,   stru,   m),  
  能够根据任意结构实体的某一个成员的地址,算出该结构实体的地址,其中参数p是指向该  
  成员的指针,stru是该结构体,m是该成员。 问题点数:20、回复次数:50Top

1 楼oo(为了名副其实,努力学习oo技术ing)回复于 2006-04-04 13:37:29 得分 0

(struct   stru*)(   (char*)p   -   (char*)&(   ((   struct   stru*)0)->m)   )   )Top

2 楼universes(及时揭帖是一种美德 | CSDN也这么黑)回复于 2006-04-04 13:40:56 得分 0

(stru   *)((char   *)p-&((stru   *)0)->m))  
   
  在《linux内核源代码情景分析》里看到过,有点忘了  
  根据自己的想法写了一个,忘高手指教。Top

3 楼universes(及时揭帖是一种美德 | CSDN也这么黑)回复于 2006-04-04 13:44:03 得分 0

to   OO:  
  呵呵,你抢先了。  
  请问一下后面那个(char   *)好像就没什么必要了吧?另外感觉你的那个struct也是多余的。。。。Top

4 楼YufengShi(浪子)回复于 2006-04-04 13:48:14 得分 0

#define   offsetof(s,m)   (size_t)&(((s   *)0)->m)  
  #define   get_struct_addr_from_member_addr(p,   stru,   m)   \  
                  (stru*)((char*)p-offsetof(stru,   m))Top

5 楼oo(为了名副其实,努力学习oo技术ing)回复于 2006-04-04 13:51:48 得分 0

后一个加char*是因为m的类型不知道,char*   -   int*会怎么样?没试过。  
  帖子在c版,所以加了struct,也许题目的意思是不需要加吧,但题目也没说明确Top

6 楼YeTimmy()回复于 2006-04-04 13:51:50 得分 0

大大的牛人。。  
  原来((   struct   stru*)0)->m可以算出结构体的偏移量  
  OO的后面好象多了个)Top

7 楼vision2004()回复于 2006-04-04 13:56:13 得分 0

linux内核中就有这个实现,当初看到他的时候,惊叹不已,呵呵Top

8 楼gjianpro(#ifndef _DEBUG)回复于 2006-04-04 13:57:44 得分 0

to   universes;:  
  oo的写法是规范的,,后面的(char   *)是必须的,,而两个struct都是可有可无的Top

9 楼jinjiajie(leorio)回复于 2006-04-04 14:05:28 得分 0

能解释一下吗?Top

10 楼jinjiajie(leorio)回复于 2006-04-04 14:34:01 得分 0

哦...了解了...不用解释了Top

11 楼cunsh(村少)回复于 2006-04-04 14:36:34 得分 0

mark  
  xuexi;Top

12 楼universes(及时揭帖是一种美德 | CSDN也这么黑)回复于 2006-04-04 14:42:00 得分 0

to   OO   and   gjianpro:  
  我觉得不用char   *,而用int或许更合理。。。。  
   
  另外:  
  YufengShi(浪子)转换为size_t就感觉有点不合适了,我在BSD中看的代码size_t最终其实是:unsigned   int或者unsigned   long   long,即为unsigned,而这里的地址在某些系统里会是一个负数。。。。。  
   
  抛砖引玉,哪位再请赐教?  
   
   
  Top

13 楼hsilz(三星五角▲▲▲★★★★★自己加星玩)回复于 2006-04-04 14:44:56 得分 0

#define   list_entry(ptr,type,member)  
            ((type*)((char*)(ptr)-(ulong)(&((type*)0)->member)))  
   
  Top

14 楼thinkinnight(逍遥)回复于 2006-04-04 14:58:15 得分 0

#define   get_struct_addr_from_member_addr(p,   stru,   m)\  
  (   (struct   stru*)(   (char   *)p   -   (unsigned   long)(&((struct   stru*)0)->m)   )   )Top

15 楼yleiou(单刀匹马)回复于 2006-04-04 15:19:11 得分 0

厉害   惊叹Top

16 楼hehe(呵呵)回复于 2006-04-04 15:28:57 得分 0

markTop

17 楼lyae(阿因)回复于 2006-04-04 15:55:10 得分 0

惊艳!...谦虚.Top

18 楼wqrz_015()回复于 2006-04-04 16:22:52 得分 0

//--winnt.h  
  //   Calculate   the   address   of   the   base   of   the   structure   given   its   type,   and   an  
  //   address   of   a   field   within   the   structure.  
  //  
   
  #define   CONTAINING_RECORD(address,   type,   field)   ((type   *)(   \  
                                                                                                      (PCHAR)(address)   -   \  
                                                                                                      (UINT_PTR)(&((type   *)0)->field)))  
  Top

19 楼lyae(阿因)回复于 2006-04-04 16:29:27 得分 0

to:   oo(为了名副其实,努力学习oo技术ing)    
  //=================================================================  
  后一个加char*是因为m的类型不知道,char*   -   int*会怎么样?没试过。  
  帖子在c版,所以加了struct,也许题目的意思是不需要加吧,但题目也没说明确  
  //=====================================================================  
  其实m的类型不知道不是没有关系吗?   "&(((struct   stru*)0)->m)"得到的已是地址偏移值,是什么指针类型没有关系,第一个"(char   *)"保证了地址计算正确(按char   1字节).第二个"(char   *)"好像就没有必要了.Top

20 楼citywanderer2005(流浪狗)回复于 2006-04-04 16:31:27 得分 0

恩,厉害!Top

21 楼leaway211(Ludwig)回复于 2006-04-04 16:39:26 得分 0

(stru   *)(   (char   *)p   -   (char*)&(((stru   *)0)->c)   )Top

22 楼fxyj2008(超级黑客)回复于 2006-04-04 19:58:51 得分 0

说实话,学了几年的C,还真不明白struct   stru*)0)->m的意思,谁能给我解释一下?  
  长长见识啊Top

23 楼sea_sharka_17()回复于 2006-04-04 20:54:20 得分 0

真得是学习啊!Top

24 楼caryyang(我爱排骨)回复于 2006-04-04 21:09:49 得分 0

linux内核的通用队列实现Top

25 楼zhouyinhui(我也飘~~过)回复于 2006-04-04 21:16:15 得分 0

回复人:oo(为了名副其实,努力学习oo技术ing)    
  (struct   stru*)(   (char*)p   -   (char*)&(   ((   struct   stru*)0)->m)   )   )  
  -----------------------  
  多了一个   )  
  Top

26 楼minsavage(帆野)回复于 2006-04-04 21:29:11 得分 0

(struct   stru*)(   (char*)p   -   (char*)&(   ((   struct   stru*)0)->m)   )   )  
    如果没有第2个(char   *)   在编译器里就会报错   告知减号两端类型不匹配  
  至少在VC6下是报错了哈Top

27 楼jruv(~~~一叶落而知天下秋~~~)回复于 2006-04-05 00:47:16 得分 0

我的想法是其实0可以换成任意值N  
  数据成员偏移量是  
  unsigned   long   offset   =   (char*)&(   ((   struct   stru*)N)->m)-(char   *)N  
  所以结构地址是(struct   stru*)(   (char*)p   -   offset   )  
   
  要这样理解:  
  把N当作一个地址,强制转换成结构类型struct   stru的首地址,   则&(struct   stru*)N)->m就是m成员的地址,那这个数据成员的偏移量就很清楚了  
  就是(char*)&(   ((   struct   stru*)N)->m)-(char   *)N  
  偏移量知道了,那结构的地址就是这个成员的绝对地址p减去这个偏移量喽  
  (struct   stru*)(   (char*)p   -   offset   )  
   
  0的情况只不过是特例而已,比用N方便,其实用上面的公式N都不需要有赋初值的,不过会有警告出现.  
   
   
   
  Top

28 楼cquazhi(阿志)回复于 2006-04-05 09:54:13 得分 0

晕了,我怎么看不懂啊???大牛能不能详细解释一下啊,我初学C呢Top

29 楼september___29()回复于 2006-04-05 10:38:42 得分 0

这儿有个解释...  
  -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  
  A_B_C_ABC(黄瓜)   (   )   信誉:100    
  #define   CONTAINING_RECORD(address,   type,   field)   \  
          ((type   *)((PCHAR)(address)   -   (ULONG_PTR)(&((type   *)0)->field)))  
  -=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=-=--=  
  这个,在我弄了两年多的Cpp的还没有遇到有这样的NB需求,想先问问你朋友在用这个东西的context是何?期待  
   
  但是,你既然问了  
  我是这样理解的:  
   
  例如:  
   
  class   CRecord{  
  public:  
        int   m_Age;  
        string   m_Name;  
        image     m_Pic;  
  //...  
  //....其它  
  }  
  是个简单的记录类型,  
   
  有  
  void   Test(){  
      CRecord   objRec;//记录对象..  
      image&     rImage   =   objRec.m_Pic;//记录对象里面的##  
       
      CRecord*   pRecord   =   CONTAINING_RECORD(&rImage,   CRecord,   m_Pic);  
    //也就是   CRecord*   pRecord   =  
    //((CRecord*)((char*)(&rImage)   -   (unsigned   long*)(&((CRecord*)0)->m_Pic)))  
  }  
   
  现在我就来解释解释  
  "(&((CRecord*)0)->m_Pic))"为什么一定要是"(&((CRecord*)0)->m_Pic))"  
  而不是"(&((CRecord*)   -2.99   )->m_Pic))"或者"(&((CRecord*)   168   )->m_Pic))"吧,好不好?  
   
  第一.Cpp的C血统是很深厚的...C在我们的电脑上无所不能,Cpp一样...掌握它..  
            不知道你平时看到C**Veiw*   p**Wnd=new   C**Veiw然后   使用   p**Wnd->m_myMenber的时候有没有思考  
    "到底是怎么回事儿"        
  因为你的P**Wnd指针本身除了保存一个地址(一个整型值)外什么信息都没有,  
  既而什么信息都没有那它怎样引用的它所指向的m_myMember对象呢?  
   
  其实,它是通过一种位偏移来得到的,"m_myMenber"名称自己本身就带有偏移的信息了  
            p**Wnd->m_myMember其实就是在   p**Wnd指针保存的值加上m_myMember的偏移值而获取m_myMember这个对象的..这是理论..  
   
  第二.((CRecord*)   "0"   )这句话告诉了你的机器,  
            从现在开始   在内存中     从[0,1,2,3,4,....sizeof(CRecord)-1]这一块内存(注意是从"零"开始的)是个"CRecord类生成的对象的内存块"(实际上这块内存很可能是保存的其它的信息,而且是你去修改就很可能感觉比较郁闷的信息)..  
            ((CRecord*)   0   )->m_Pic)这句话告诉你的机器在[0,1,2,3,4,....sizeof(CRecord)-1]这块内存找到一个m_Pic对象(实际上也不存在这个m_Pic对象,没有关系)  
            (&((CRecord*)0)->m_Pic))返回上面你找到的虚拟的"m_Pic对象"的地址,但是要注意(CRecord*)   0是(CRecord*)   0,而不是(CRecord*)   12也不是(CRecord*)   -9.99;所以(ULONG_PTR)(&((CRecord*)0)->m_Pic))实际上是一个偏移量的值!!  
            然后当前你m_Pic地址减去你的偏移量当然就是包括m_Pic的包容类的对象的地址拉  
  (注意包容类的地址必须强制转换为(char*)也就是(PCHAR)(address)不能直接用(address)  
      (why?   这个你应该明白的,再要我说就是对其它人智商的侮辱了,对不??)  
  完了在把它强制转换到(type   *)类型也就是(CRecord*)类型  
   
  这样说下面的语句应该是很明白了  
  ((CRecord*)((char*)(&rImage)   -   (unsigned   long*)(&((CRecord*)0)->m_Pic)))  
                  ((type   *)((PCHAR)(address)   -   (ULONG_PTR)(&((type   *)0)->field)))  
  但是我开始说了用下面的方法好一些,也好明白一些;  
   
        image   CRecord::*pMb   =   &CRecord::m_Pic;  
        CRecord*   pRec=(CRecord*)((int)&objRec.m_Pic-   *(int*)&pMb);  
  你说呢?  
   
  ----  
  看来sun   也不难进啊Top

30 楼september___29()回复于 2006-04-05 10:55:12 得分 0

哈哈,看了楼上sep_29的解答是不是有醍醐灌顶之大觉大悟之感啊Top

31 楼hotonion(菜鸟怎么变大牛呢?)回复于 2006-04-05 11:16:57 得分 0

markTop

32 楼qingyuan18(zealot_tang)回复于 2006-04-05 13:17:56 得分 0

靠,牛人!Top

33 楼skyofwind(风之吻)回复于 2006-04-05 13:44:23 得分 0

佩服的无语言了哈,一个字。。。。强!!Top

34 楼cattlenzq(吃狼的豆腐(不要给分了,散起来真麻烦!))回复于 2006-04-05 14:34:05 得分 0

markTop

35 楼cutenoob(cute )回复于 2006-04-05 14:39:47 得分 0

markTop

36 楼kentxp(kent)回复于 2006-04-05 15:03:49 得分 0

mark   方便查找Top

37 楼noneone(noneone)回复于 2006-04-05 15:18:34 得分 0

markTop

38 楼mengge(踏岸寻柳)回复于 2006-04-05 17:12:16 得分 0

不错,毕竟的大公司的题目!Top

39 楼cg5353(努力学习中)回复于 2006-04-05 18:47:33 得分 0

markTop

40 楼fxyj2008(超级黑客)回复于 2006-04-05 19:18:48 得分 0

(struct   stru*)(   (char*)p   -   (char*)&(   ((   struct   stru*)0)->m)   )   )  
   
  看了各位的答案,稍微理解了一下,  
  但是觉得很奇怪,将常数转化为struct   stru*     类型,这完全是编译器决定答案的啊,这种题目还有意思的啊,假如我重新设计一个编译器,那答案是不是变了呢??  
  竟然还有人称什么         强     ,,牛人       。。       大公司的     题目  
  如果这也算什么强的话,那设计编译器的人呢,写OS的人呢??  
  真正强的人应该是对计算机系统有很深的理解,比如写编译后端的人!  
  可惜还没有看到国内有什么商用的编译器哦!Top

41 楼whopkl(清明)回复于 2006-04-05 19:59:22 得分 0

牛人一个Top

42 楼ruodeer(看我的个性签名都给我分)回复于 2006-04-05 22:40:24 得分 0

markTop

43 楼closetome(即鹿无虞,惟入于林中。君子几,不如舍。往吝。)回复于 2006-04-05 23:02:49 得分 0

mark  
  正在看linux,这个宏风格应该是linux下的Top

44 楼wangever(环环)回复于 2006-04-06 01:37:06 得分 0

markTop

45 楼mengge(踏岸寻柳)回复于 2006-04-06 08:25:19 得分 0

说白了吧,精髓只在这里:  
  (size_t)&(((struct   stru   *)0)->m) //   偏移量  
  这里的这个0,似乎不可等闲视之,应该是:  
  (size_t)&(((struct   stru   *)NULL)->m)  
  因为,#define   NULL   (void   *)0  
   
  你试一试将0换做别的数字,看看结果是否还是正确的。Top

46 楼howyougen(夫孝,德之本也,教之所由生也)回复于 2006-04-06 08:51:31 得分 0

markTop

47 楼lemon_1104()回复于 2006-04-13 19:52:44 得分 0

学习Top

48 楼HopeInDark(子弹)回复于 2006-04-14 10:00:42 得分 0

MARKTop

49 楼renwxing()回复于 2006-04-14 11:55:01 得分 0

#define   list_entry(ptr,type,member)   \  
            (     (type*)(   (char   *)(ptr)   -   (unsigned   long)(&((type*)0)->member)   )     )  
   
  (char   *)   and   (unsigned   long)  
  (char   *)   and   (char   *)  
  (unsigned   long)   and   (unsigned   long)Top

50 楼gamedr()回复于 2006-04-14 13:04:31 得分 0

学习  
  Top

相关问题

关键词

得分解答快速导航

  • 帖主:lihui4003

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo