在c中查找结构元素的偏移量

时间:2013-09-11 19:10:23

标签: c struct

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

有人可以解释我如何找到int k的偏移量,以便我们找到int i的地址吗?

6 个答案:

答案 0 :(得分:35)

使用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 :(得分:7)

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引用结构i中结构x中的字段foo&foo.x.i为您提供字段foo.x.i的地址。 同样,&foo.y.k会为您提供foo.y.k的地址; &foo为您提供结构foo的地址。

foo的地址中减去foo.x.i的地址会为您提供从foofoo.x.i的偏移量。

正如Gangadhar所说,你可以使用offsetof()宏而不是我给出的指针算法。但是首先要理解指针算法是很好的。

答案 2 :(得分:7)

问题问题已经过去了3年,我为了完整起见而添加了答案。

获得结构成员偏移量的hacky方式就像这样

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

它看起来不漂亮,我无法想到纯C中的任何东西(它可以让你获得成员的偏移,而不知道结构的任何其他内容。我相信{{1} } macro以这种方式定义。

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

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

本文中可以找到更详细的解释:

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

答案 3 :(得分:4)

如上所述,您应该使用offsetof()中的<stddef.h>宏,它会将偏移量生成为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

答案 4 :(得分:0)

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

#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

答案 5 :(得分:0)

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

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的基址。