【问题标题】:Finding offset of a structure element in c在c中查找结构元素的偏移量
【发布时间】:2019-12-07 01:17:00
【问题描述】:
struct a
{
    struct b
    {
        int i;
        float j;
    }x;
    struct c
    {
        int k;  
        float l;
    }y;
}z;

谁能解释一下如何找到int k 的偏移量,以便我们找到int i 的地址?

【问题讨论】:

  • 布局如下 [ sizeof(int), sizeof(float), sizeof(int), sizeof(float) ]
  • 你可以从y的开头找到k的偏移量,或者从z的开头;您可以从x 的开头或z 的开头找到i 的偏移量。但是,在给定i 的偏移量的情况下,基本上没有保证找到k 的偏移量的方法。您可以做出不可移植的假设来得出答案,但是当您可以提出不涉及假设的可移植方法时,为什么要这样做。
  • @koodawg 没必要。这取决于编译器和目标架构。有时编译器可能会添加填充以确保字段找到具有所需对齐的地址。 software.intel.com/en-us/blogs/2011/08/18/…

标签: c struct


【解决方案1】:

使用offsetof() 查找与z 开头或x 开头的偏移量。

offsetof() - 结构成员的偏移量

概要

   #include <stddef.h>

   size_t offsetof(type, member);

offsetof() 返回字段成员的偏移量 结构类型的开始。

示例

   #include <stddef.h>
   #include <stdio.h>
   #include <stdlib.h>

   int
   main(void)
   {
       struct s {
           int i;
           char c;
           double d;
           char a[];
       };

       /* Output is compiler dependent */

       printf("offsets: i=%ld; c=%ld; d=%ld a=%ld\n",
               (long) offsetof(struct s, i),
               (long) offsetof(struct s, c),
               (long) offsetof(struct s, d),
               (long) offsetof(struct s, a));
       printf("sizeof(struct s)=%ld\n", (long) sizeof(struct s));

       exit(EXIT_SUCCESS);
   }

如果您使用 GCC 编译,您将在 Linux 上获得以下输出:

       offsets: i=0; c=4; d=8 a=16
       sizeof(struct s)=16

【讨论】:

  • -1 :该问题专门要求如何在 nested 结构中找到元素的偏移量...这篇文章 not 回答了这个问题问题。
  • @BlueChip 当然可以,您只需要利用人类思维的力量。 offsetof(struct a, y) + offsetof(struct c, k) 工作得很好。
【解决方案2】:

问这个问题已经 3 年了,为了完整起见,我正在添加我的答案。

获取结构成员偏移量的hacky方法是这样的

printf("%p\n", (void*)(&((struct s *)NULL)->i));

它看起来不漂亮,我想不出纯 C 中的任何东西(它可以让你得到成员的偏移量,而不知道关于结构的任何其他内容。我相信 offsetof 宏在此定义时尚。

作为参考,这个技术在 linux 内核中使用,查看 container_of 宏:

http://lxr.free-electrons.com/source/scripts/kconfig/list.h#L18

可以在这篇文章中找到更详细的解释:

http://radek.io/2012/11/10/magical-container_of-macro/

【讨论】:

  • 能否请您澄清&amp;((struct s *)NULL)-&gt;i 将如何正常工作,但((struct s *)NULL)-&gt;i 给出分段错误
  • @Karthik -&gt; 运算符的优先级高于 &amp; 运算符。因此&amp;((struct s *)NULL)-&gt;i 等价于&amp;(((struct s *)NULL)-&gt;i),就像说take address of (((struct s *)NULL)-&gt;i)
  • @Silen,为什么我们在 &((struct s *)NULL)->i 中添加 NULL?
  • @EswaranPandi 它创建一个指向 struct s 的空指针,获取其成员 i 并获取其地址。成员的地址是结构地址+偏移量。由于struct地址为0,所以得到的地址就是成员的偏移量。
【解决方案3】:
struct a foo;
printf("offset of k is %d\n", (char *)&foo.y.k - (char *)&foo);    
printf("offset of i is %d\n", (char *)&foo.x.i - (char *)&foo);

foo.x.i 引用结构体x 结构体foo 中的字段i&amp;foo.x.i 为您提供字段 foo.x.i 的地址。 同样,&amp;foo.y.k 给你foo.y.k 的地址; &amp;foo 为您提供结构 foo 的地址。

foo.x.i 的地址中减去foo 的地址,得到从foofoo.x.i 的偏移量。

正如 Gangadhar 所说,您可以使用 offsetof() 宏而不是我给出的指针算法。不过还是先了解一下指针算法就好了。

【讨论】:

  • 试试看,看看你会得到什么。可能 i 为 0,k 为 8。请参阅上面尼克的评论。
  • 可能是foo.x.i refers to the field i in the struct x in the struct foo(x vs. y)。
  • OP似乎在寻找i的地址,所以在我看来你可以停在&amp;foo.x.i
  • 这个问题很模糊,我认为信息越多越好。他问了k,所以我也给了他k。
【解决方案4】:

如前所述,您应该使用来自&lt;stddef.h&gt;offsetof() 宏,它将偏移量作为size_t 值生成。

例如:

#include <stddef.h>
#include <stdio.h>
#include "struct_a.h"  /* Header defining the structure in the question */

int main(void)
{
    size_t off_k_y = offsetof(struct c, k);
    size_t off_k_z = offsetof(struct a, y.k);
    size_t off_i_x = offsetof(struct b, i);
    size_t off_i_z = offsetof(struct a, x.i);

    printf("k = %zu %zu; i = %zu %zu\n", off_k_y, off_k_z, off_i_x, off_i_z);
    return 0;
}

示例输出:

k = 0 8; i = 0 0

【讨论】:

  • offsetof() 完美 +1。
  • 先生,感谢您提供信息丰富的示例,但我想知道为什么我们需要确定结构元素的偏移量?例如,为什么要使用不同结构的 d_name?你能说吗?
【解决方案5】:

要找到偏移量,这是我们可以解决的一种方法。

struct a{
    struct b
    {
        int i;
        float j;
    }x;
    struct c
    {
        int k;
        float l;
    }y;
}z;

int main(){
    struct a* foo = &z;

    printf("%d\n", foo);                  //address of z
    printf("%d\n", &(foo->y));            //address of z.y
    printf("%d\n", &( (&(foo->y))->k ));  //address of z.y.k


    int offset_k = (char*)&( (&(foo->y))->k ) -  (char*)foo ;
    printf("%d\n", offset_k);             

    return 0;
}

输出将与此类似:

4225552     //address of z
4225560     //address of z.y
4225560     //address of z.y.k
8           //offset

在这种特殊情况下,由于 int i 是结构的第一个成员,因此结构的基地址也将是 int i 的基地址。否则,您可以以类似的方式计算 int i 的偏移量。

int offset_i = (char*)&( (&(foo->x))->i ) -  (char*)foo;  //0 in this case

注意:偏移量将是负数或正数,具体取决于您如何定义它(如果它是相对于基地址或成员 z.y.k)。在这里,它被定义为相对于 struct 的基地址。

【讨论】:

    【解决方案6】:

    这是一个通用的解决方案:

    #if defined(__GNUC__) && defined(__GNUC_MINOR__)
    #  define GNUC_PREREQ(minMajor, minMinor) \
             ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((minMajor) << 16) + (minMinor))
    #else
    #  define GNUC_PREREQ 0
    #endif
    
    #if GNUC_PREREQ(4, 0)
    #  define OFFSETOF(type, member) ((int)__builtin_offsetof(type, member))
    #else
    #  define OFFSETOF(type, member) ((int)(intptr_t)&(((type *)(void*)0)->member) )
    #endif
    

    【讨论】:

    • 一个使用示例会很好! :)
    • @Clearlight,我看过这个定义:#define GNUC_PREREQ(minMajor, minMinor) \ ((GNUC GNUC_MINOR > = ((minMajor) GNUC 和 minMajor 16 位?只有在那之后添加未成年人。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-13
    相关资源
    最近更新 更多