Finding offset of a structure element in c
Asked Answered
E

6

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?

Eckert answered 11/9, 2013 at 19:10 Comment(3)
It's layed out as so [ sizeof(int), sizeof(float), sizeof(int), sizeof(float) ]Burdett
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.Percy
@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. software.intel.com/en-us/blogs/2011/08/18/…Gloaming
M
63

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
Metalinguistics answered 11/9, 2013 at 19:34 Comment(2)
-1 : The question specifically requests how to find the offset of an element in a nested struct ...This post does not answer that question.Illusory
@Illusory 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.Dashtilut
A
26

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/

Adnopoz answered 1/10, 2016 at 10:37 Comment(4)
Could you please clarify how &((struct s *)NULL)->i would work fine but ((struct s *)NULL)->i gives segmentation faultOconnell
@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).Raffo
@Silen, why we are adding NULL in &((struct s *)NULL)->i?Calypso
@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.Newland
P
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.

Pongid answered 11/9, 2013 at 19:15 Comment(4)
Try it, see what you get. Probably 0 for i, and 8 for k. See Nick's comment above.Pongid
Maybe foo.x.i refers to the field i in the struct x in the struct foo (x vs. y).Mccready
The OP seems to be looking for the address of i, so seems to me you can stop at &foo.x.i.Gaby
The question was vague, I figured the more info the better. He asked about k, so I gave him k as well.Pongid
P
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
Percy answered 11/9, 2013 at 19:37 Comment(1)
Sir thank you for your informative example but I wish to know that why we need to determine offset of an element of a structure? For example, why for d_name of dirent structure? Could you say?Bibi
E
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.

Erode answered 6/7, 2019 at 4:57 Comment(3)
A usage example would be nice! :)Tough
@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 youDrachm
@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"?Erode
C
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.

Civilian answered 6/12, 2019 at 17:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.