C 给定指向结构中成员a的指针,编写一个例程,返回指向该结构的指针
这是我在某个论坛上看到的一个采访问题。我一直想弄清楚它是怎么工作的,但我不太明白。有人能解释一下它是怎么工作的吗 问:给定一个指向结构中成员a的指针,编写一个例程返回指向该结构的指针C 给定指向结构中成员a的指针,编写一个例程,返回指向该结构的指针,c,struct,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*)(
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);
}
可以使用offsetof宏
struct s* get_s_ptr(int *a_ptr)
{
return (struct s*)((char*)a_ptr - offsetof(struct s,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所指出的,您应该尽量避免使用此代码。几乎总有更好的办法。答案是:没有。它不起作用,即使乍一看它似乎“起作用”。“应答”试图取消对空指针的引用,从而导致未定义的行为。所以,除非你的“工作”概念包括未定义的行为,否则这个答案是行不通的 这个解决方案还有更多的问题,除了试图解除空指针的失效(尽管仅此一点就足以将“答案”扔进垃圾箱)。另一个问题是
(struct s*)0
的结果是struct s*
类型的空指针。该语言不保证空指针的实际物理值。If很容易成为类似于0xBAADFOOD
的东西,这会立即破坏“答案”的预期功能
隐含技术的正确实现将涉及标准的offsetof
宏(已经在Nyan的回答中提出了,但我将再次重复)
我认为这会有帮助
/* 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;
}
所以在你的情况下
return (struct s*) ((char *) a_ptr - offsetof(struct s, a));
- 将aptr转换成字符*
- 将
wrt的偏移量减去a
struct s
- 转换为结构s*
- 返回
结果ptr
offsetof
是标准库组件。就接口而言,它只是C,而它的实现不是C和/或不要求是C。换句话说,在您的C代码中,您可能不允许做完全可以接受的offsetof
。这里有一个空指针的解引用。运算符->
是一个解引用。@迈克:你的试验结果只意味着它“工作”在某个平台上。当然,这并不能使它成为C语言中的法律解决方案。您对一段完全错误的、非标准的、通常很糟糕的代码给出了非常详细的解释。
/* 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));