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

Ste*_*eve 9 c struct

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

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

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

struct s *get_s_ptr(int *a_ptr)
{
   // implement this.
}
Run Code Online (Sandbox Code Playgroud)

答案是:

struct s* get_s_ptr(int *a_ptr)
{
   return (struct s*)((char*)a_ptr - (int)&((struct s*)0)->a);
}
Run Code Online (Sandbox Code Playgroud)

Nor*_*sey 12

它是如何工作的?

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

address of struct member s->a == s + byte offset of a
Run Code Online (Sandbox Code Playgroud)

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

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

address of struct member s->a - byte offset of a == s
Run Code Online (Sandbox Code Playgroud)

在这个问题中,你得到了地址s->a,但是你必须找出字节偏移量.要做到这一点,你用原来的公式再次s设置为零:

address of struct member s->a where s is zero == zero + byte offset of a 
                                              == byte offset of a
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

最后的步骤:

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

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

  • 你给出了一个完全错误的,非标准的,通常是*糟糕的代码片段的详细解释. (3认同)

AnT*_*AnT 6

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

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

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

struct s* get_s_ptr(int *a_ptr)
{
   return (struct s*) ((char *) a_ptr - offsetof(struct s, a));
}
Run Code Online (Sandbox Code Playgroud)

  • &(pObj->a) 与 &( (*pObj).a) 相同。因此,如果 pObj 为 NULL,则取消引用 NULL 指针。 (2认同)