这是我在某个论坛上看到的访谈问题。我一直试图弄清楚它是如何工作的,但我不太明白。有人可以解释它是如何工作的吗?
问:给定一个结构中成员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);
}
答案 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
最后的步骤:
a_ptr
将转换为char *
。struct s *
。附录:正如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