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

Can anybody explain me how to find the offset of int k so that we can find the address of int i?

SurvivalMachine
  • 7,946
  • 15
  • 57
  • 87
MSB
  • 453
  • 1
  • 4
  • 6
  • It's layed out as so [ sizeof(int), sizeof(float), sizeof(int), sizeof(float) ] – Mike Makuch Sep 11 '13 at 19:17
  • 1
    You can find the offset of `k` from the start of `y`, or from the start of `z`; you can find the offset of `i` from the start of `x` or from the start of `z`. However, there is essentially no guaranteed way to find the offset of `k` given the offset of `i`. You can make non-portable assumptions to come up with an answer, but why would you do that when you can come up with a portable method that doesn't involve assumptions. – Jonathan Leffler Sep 11 '13 at 19:26
  • 2
    @koodawg Not necessary. It depends on the compiler and target architecture. Sometimes the compiler may add padding to ensure that fields find the addresses with the desired alignment. https://software.intel.com/en-us/blogs/2011/08/18/understanding-x86-vs-arm-memory-alignment-on-android – Enyby Oct 25 '15 at 17:00

6 Answers6

60

Use offsetof() to find the offset from the start of z or from the start of x.

offsetof() - offset of a structure member

SYNOPSIS

   #include <stddef.h>

   size_t offsetof(type, member);

offsetof() returns the offset of the field member from the start of the structure type.

EXAMPLE

   #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);
   }

You will get the following output on a Linux, if you compile with GCC:

       offsets: i=0; c=4; d=8 a=16
       sizeof(struct s)=16
Lii
  • 11,553
  • 8
  • 64
  • 88
Gangadhar
  • 10,248
  • 3
  • 31
  • 50
  • 1
    -1 : The question specifically requests how to find the offset of an element in a **nested** struct ...This post does **not** answer that question. – BlueChip Jul 28 '17 at 00:02
  • 13
    @BlueChip Sure it does, you just need to take advantage of the power of your human mind. `offsetof(struct a, y) + offsetof(struct c, k)` works just fine. – Jason C Jul 06 '19 at 18:37
25

It's been 3 years since the question has been asked, I'm adding my answer for the sake of completeness.

The hacky way of getting the offset of a struct member goes like this

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

It doesn't look pretty, I can't think of anything in pure C (which can get you the offset of the member, without knowing anything else about the structure. I believe the offsetof macro is defined in this fashion.

For reference, this technique is used in the linux kernel, check out the container_of macro :

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

A more elaborate explanation can be found in this article:

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

silen
  • 524
  • 6
  • 5
  • 1
    Could you please clarify how `&((struct s *)NULL)->i` would work fine but `((struct s *)NULL)->i` gives segmentation fault – Karthik Raj Palanichamy Apr 24 '18 at 06:36
  • 2
    @Karthik The `->` operator has higher precedence than the `&` operator. Thus `&((struct s *)NULL)->i` is equivalent to `&(((struct s *)NULL)->i)`, which is like saying `take address of (((struct s *)NULL)->i)`. – Jasha May 18 '18 at 07:03
  • @Silen, why we are adding NULL in **&((struct s *)NULL)->i**? – Eswaran Pandi Mar 05 '20 at 12:28
  • 1
    @EswaranPandi it creates a null pointer to struct s, gets its member i and takes its address. The address of a member is struct address + offset. Since struct address is 0, the address you get equals the offset of the member. – GDavid Aug 03 '20 at 15:49
10
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 refers to the field i in the struct x in the struct foo. &foo.x.i gives you the address of the field foo.x.i. Similarly, &foo.y.k gives you the address of foo.y.k; &foo gives you the address of the struct foo.

Subtracting the address of foo from the address of foo.x.i gives you the offset from foo to foo.x.i.

As Gangadhar says, you can use the offsetof() macro rather than the pointer arithmetic I gave. But it's good to understand the pointer arithmetic first.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Charlie Burns
  • 6,994
  • 20
  • 29
7

As already suggested, you should use the offsetof() macro from <stddef.h>, which yields the offset as a size_t value.

For example:

#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;
}

Example output:

k = 0 8; i = 0 0
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

Here's a generic solution that works with both newer and older versions of GNU C:

<!-- language: C -->

#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

UPDATE: Someone asked for a usage example:

struct foo {
   int bar;
   char *baz;
}

printf("Offset of baz in struct foo = %d\n",
       OFFSETOF(foo, baz));

Would print 4, if int compiles into 4 bytes on the architecture of the machine it runs on.

clearlight
  • 12,255
  • 11
  • 57
  • 75
  • 1
    A usage example would be nice! :) – Sajjon May 11 '20 at 09:27
  • @Clearlight, I have seen this definition: # define GNUC_PREREQ(minMajor, minMinor) \ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((minMajor) << 16) + (minMinor)) in some other place of Glibc as well. Can you please explain what's the purpose of this calculation? why are we shifting __GNUC__ and minMajor 16 Bits to the left? and only after that adding the minor. Thank you – Arie Charfnadel Jun 15 '20 at 23:09
  • @ArieCharfnadel didn't see your question before. GNU compiler saves maj/min as two separate values, instead of as one value like "3.2", for example, so software can more easily test maj and min values separately. These macros combine maj & min, for the sake of clearer comparison to other version version numbers.. Shifting and stashes them into a single 4-byte `int` in such a way as to preserve the *relative* **magnitude** of maj & min values mathematically. By doing same to both the GNU version number & major/minor values the comparisons are simpler and clearer similar to "is 3.2 > 2.5"? – clearlight Jul 14 '22 at 12:09
1

To find the offset, this is one way we can go about it.

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;
}

Output would be similar to this:

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

In this particular case, since int i is the first member of the struct, the base address of the struct will be that of int i as well. Otherwise, you could compute the offset of int i in a similar manner.

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

NOTE: The offset will be negative or positive depending on how you define it (if it's with respect to base address or member z.y.k). Here, it is defined to be with respect to base address of struct.