这是我在一些论坛上看到的面试问题.我一直试图弄清楚它是如何工作的,但我不太明白.有人可以解释它是如何工作的吗?
问:给定一个结构中成员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)
最后的步骤:
a_ptr为单位进行减法,将转换为char *.struct s *.附录:正如Eli Bendersky指出的那样,你应该尽量避免使用这些代码的情况.几乎总有一种更好的方法.
答案是:它没有.它不起作用,即使它看起来似乎"工作"的第一眼."回答"尝试取消引用空指针,这会导致未定义的行为.因此,除非您的"工作"想法包含未定义的行为,否则该答案不起作用.
该解决方案存在更多问题,除了尝试对空指针进行去激活(尽管仅此一点就足以将"回答"扔到垃圾箱).另一个问题是结果(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));
}
Run Code Online (Sandbox Code Playgroud)