Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 给定指向结构中成员a的指针,编写一个例程,返回指向该结构的指针_C_Struct - Fatal编程技术网

C 给定指向结构中成员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*)(

这是我在某个论坛上看到的一个采访问题。我一直想弄清楚它是怎么工作的,但我不太明白。有人能解释一下它是怎么工作的吗

问:给定一个指向结构中成员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);
}

可以使用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
最后步骤:

  • 为了使算术C合法,该字节偏移量被转换为整数
  • 为了确保减法是以字节为单位进行的,
    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转换成字符*
    • a
      wrt的偏移量减去
      struct s
    • 转换为结构s*
    • 返回
      结果ptr

    你在问什么?对不起,我在标题中有问题,但不是帖子本身。现在已修复。同意“NULL”指针。理论上它可能是非零的,这会搞糟一切。但是,没有取消对该指针的引用。如果你看一下“offsetof”的定义,你会看到完全相同的东西。也就是说,写入&(pObj->a)不会取消引用任何内容。因为表达式的结果是地址。这只是一个算术&(pObj->a)与&(*pObj.a)相同。所以,如果pObj为NULL,它将取消对NULL指针的引用。我在这里尝试过:。((结构s*)0)->a导致seg故障,而&((结构s*)0)->a导致正确偏移。有什么想法吗?无论如何,offsetof()可能是最好的方法。@valdo:offsetof在内部做的事与我们无关
    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));