给定一个结构中成员a的指针,编写一个返回指向结构的指针的例程

时间:2010-06-20 02:24:31

标签: c struct

这是我在某个论坛上看到的访谈问题。我一直试图弄清楚它是如何工作的,但我不太明白。有人可以解释它是如何工作的吗?

问:给定一个结构中成员a的指针,编写一个返回指向结构的指针的例程。

struct s 
{
   ...
   int a;
   …
};

struct s *get_s_ptr(int *a_ptr)
{
   // implement this.
}

答案是:

struct s* get_s_ptr(int *a_ptr)
{
   return (struct s*)((char*)a_ptr - (int)&((struct s*)0)->a);
}

4 个答案:

答案 0 :(得分:12)

  

它是如何运作的?

这里的基本方程(所有算术以字节为单位)是

address of struct member s->a == s + byte offset of a

鉴于s的类型,单个编译器和单个目标机器,它们确定了a的字节偏移量 - 对于类型s的每个结构都是相同的。

你被给了左手边,你的面试官要求你恢复s。你可以通过获得一个新的等式来做到这一点;从两边减去字节偏移量:

address of struct member s->a - byte offset of a == s

在问题中,你给出地址s->a,但你必须找出字节偏移量。要执行此操作,请再次使用原始等式 ,并将s设置为零:

address of struct member s->a where s is zero == zero + byte offset of a 
                                              == byte offset of a

C中的左侧构建如下

struct pointer s where s is zero                            (struct s *)0
struct member s->a where s is zero                          ((struct s*)0)->a
address of s->a where s is zero                             &((struct s*)0)->a

最后的步骤:

  1. 要使算术合法C,此字节偏移量将转换为整数。
  2. 为了确保以字节为单位进行减法,a_ptr将转换为char *
  3. 要为结果提供正确的类型,差异将转换为struct s *

  4. 附录:正如Eli Bendersky指出的那样,你应该尽量避免使用这些代码的情况。几乎总有一种更好的方法。

答案 1 :(得分:6)

答案是:它没有。它不起作用,即使它看起来似乎“工作”的第一眼。 “回答”尝试取消引用空指针,这会导致未定义的行为。因此,除非您的“工作”想法包含未定义的行为,否则该答案不起作用。

该解决方案存在更多问题,除了尝试对空指针进行去激活(尽管仅此一点就足以将“回答”扔到垃圾箱)。另一个问题是(struct s*) 0的结果是struct s *类型的空指针。该语言不保证空指针的实际物理值。如果可能很容易就像0xBAADFOOD那样会立即搞砸“答案”的预期功能。

隐含技术的正确实现将涉及标准offsetof宏(已在Nyan的答案中提出,但我将再重复一次)

struct s* get_s_ptr(int *a_ptr)
{
   return (struct s*) ((char *) a_ptr - offsetof(struct s, a));
}

答案 2 :(得分:4)

您可以使用offsetof宏。

struct s* get_s_ptr(int *a_ptr)
{
   return (struct s*)((char*)a_ptr - offsetof(struct s,a) );
}

我迟到了。我的网络连接很慢。

答案 3 :(得分:1)

认为这会有所帮助,

/* offsetof example */
#include <stdio.h>
#include <stddef.h>

struct mystruct {
    char singlechar;
    char arraymember[10];
    char anotherchar;
};

int main ()
{
    printf ("offsetof(mystruct,singlechar) is %d\n",offsetof(mystruct,singlechar));
    printf ("offsetof(mystruct,arraymember) is %d\n",offsetof(mystruct,arraymember));
    printf ("offsetof(mystruct,anotherchar) is %d\n",offsetof(mystruct,anotherchar));

    return 0;
}

<强>输出:

offsetof(mystruct,singlechar) is 0
offsetof(mystruct,arraymember) is 1
offsetof(mystruct,anotherchar) is 11

所以在你的情况下,

return (struct s*) ((char *) a_ptr - offsetof(struct s, a));
  • aptr转换为char *
  • a wrt的偏移量减去struct s
  • 施放到struct s*
  • 返回resultant ptr