1

Say if I have a struct as:

struct simple_struct_1
{
  long long a;
  char b;
  long c;
};

Address of a is: 0x7ffd415c8b20 Address of b is: 0x7ffd415c8b28 Address of c is: 0x7ffd415c8b30 size of simple_struct_1 is 24

I have printed the address of each member and the size of the struct, how do I show how this struct is laid down in memory? Like if in the simple_struct_1, a occupies 111 bytes and has 222 padding bytes after which b occupies 333 bytes with 0 padding bytes after it, and c occupies 444 bytes with 555 bytes of padding after it.

MCG
  • 1,011
  • 1
  • 10
  • 21

3 Answers3

4

You can use offsetof and sizeof to get details on each individual field and the size of the structure as a whole, such as with:

printf ("a      is %d@%d\n", sizeof(simple_struct_1.a), offsetof(simple_struct_1, a));
printf ("b      is %d@%d\n", sizeof(simple_struct_1.b), offsetof(simple_struct_1, b));
printf ("c      is %d@%d\n", sizeof(simple_struct_1.c), offsetof(simple_struct_1, c));
printf ("struct is %d@0\n",  sizeof(simple_struct_1));

That should enable you to work out:

  • the offsets and sizes of all fields;
  • the gaps between the fields; and
  • the gap after the last field (combine its offset and size with the size of the entire structure.

Don't worry about padding before the first field, the ISO standard forbids that.

For example, let's say you see the following output on the left, the sizes and gaps are shown on the right:

a      is 16@0        16 bytes for a long long
                      no gap (0 + 16 = 16, next at 16)
b      is 1@16         1 byte  for a char
                       7 bytes gap (16 + 1 = 17, next at 24)
c      is 8@24         8 bytes for a long
struct is 32@0        no gap at end (24 + 8 = 32, next at 32)
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

You can use the offsetof() macro to find the offset in bytes of each field from the first member (which must have the same address as the struct since no padding is allowed to precede the first member).

Combining this information with the sizes of the various members (and the size of the whole struct to find the number of trailing padding bytes), obtained using the sizeof operator, allows one to deduce where the padding bytes are. Here is a program that prints out member addresses and offsets. It also prints a graphic representation of member bytes and padding bytes; dashes indicate padding bytes.

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

struct simple_struct_1 {
    long long a;
    char b;
    long c;
};

char * graph_member(char *ptr, size_t member_sz, size_t padding_sz);

int main(void)
{
    struct simple_struct_1 my_struct;

    printf("sizeof (struct simple_struct_1) = %zu\n",
           sizeof (struct simple_struct_1));
    putchar('\n');

    void *ptra = &(my_struct.a);
    void *ptrb = &(my_struct.b);
    void *ptrc = &(my_struct.c);

    size_t offset_a = offsetof(struct simple_struct_1, a);
    size_t offset_b = offsetof(struct simple_struct_1, b);
    size_t offset_c = offsetof(struct simple_struct_1, c);

    /* Allocate memory for struct padding visualization */
    char *graph = malloc(sizeof my_struct + 1);

    if (graph == NULL) {
        perror("Virtual memory exhausted");
        exit(EXIT_FAILURE);
    }

    char *ptr = graph;

    printf("&(my_struct.a) = %p\n", ptra);
    printf("sizeof my_struct.a = %zu\n", sizeof my_struct.a);
    putchar('\n');
    ptr = graph_member(ptr,
                       sizeof my_struct.a,
                       offset_b - sizeof my_struct.a);

    printf("&(my_struct.b) = %p\n", ptrb);
    printf("sizeof my_struct.b = %zu\n", sizeof my_struct.b);
    printf("&(my_struct.b) - &(my_struct.a) = %zu\n", offset_b - offset_a);
    putchar('\n');
    ptr = graph_member(ptr,
                       sizeof my_struct.b,
                       offset_c - offset_b - sizeof my_struct.b);

    printf("&(my_struct.c) = %p\n", ptrc);
    printf("sizeof my_struct.c = %zu\n", sizeof my_struct.c);
    printf("&(my_struct.c) - &(my_struct.b) = %zu\n", offset_c - offset_b);
    putchar('\n');
    ptr = graph_member(ptr,
                       sizeof my_struct.c,
                       sizeof my_struct - offset_c - sizeof my_struct.c);

    /* Null-terminate graph string and display */
    ptr = '\0';
    puts(graph);

    free(graph);

    return 0;
}

char * graph_member(char *ptr, size_t member_sz, size_t padding_sz)
{
    /* Indicate member */
    for (size_t i = 0; i < member_sz; i++) {
        *ptr = '*';
        ++ptr;
    }

    /* Indicate padding */
    for (size_t i = 0; i < padding_sz; i++) {
        *ptr = '-';
        ++ptr;
    }

    return ptr;
}

Sample program output:

sizeof (struct simple_struct_1) = 24

&(my_struct.a) = 0x7ffee4af4610
sizeof my_struct.a = 8

&(my_struct.b) = 0x7ffee4af4618
sizeof my_struct.b = 1
&(my_struct.b) - &(my_struct.a) = 8

&(my_struct.c) = 0x7ffee4af4620
sizeof my_struct.c = 8
&(my_struct.c) - &(my_struct.b) = 8

*********-------********
ad absurdum
  • 19,498
  • 5
  • 37
  • 60
0

You can try to use pahole (poke -a -hole). This will help exactly how you need it.

Here is a reference to it. pahole

user2736738
  • 30,591
  • 5
  • 42
  • 56