sakthi
sakthi

Reputation: 705

Memory layout for nested structure in c

I understand the structure's concept in C. I also understand how the structure is stored in memory. So I have created follwoing stuff:

  struct tag1 {
      char a;
      int b;
  }var1;

The size of the structure is 8 bytes(in gcc).

Memory layout example.

 -----------
|  |  |  |  | ---> char a (only 1 byte is used and remaining 3 bytes are padding)
 -----------
|  |  |  |  | ---> int b (4 byte is used)
 -----------

Now i have some doubt in this sample program. How the nested structure is stored in memory.

  struct tag1{
      int a;
      struct tag2{
          long b;
      }var1;
  }var2;

Upvotes: 8

Views: 3071

Answers (3)

ryyker
ryyker

Reputation: 23236

As noted in comments, the exact layout of a struct in memory is implementation specific. Also generally true, layout is affected by member types, memory addressing (32bit or 64bit) and pragma pack calls that adjust the way alignment occurs along memory boundaries.

An example of what I see on my system when I place two instances of your original struct as sub-struct members into yet another struct (for context, and to force contiguous memory assignment), then assigned values to an instance of that struct to provide distinguishable (non-zero) content in the memory layout:
(32bit addressing, with no pragma statements)

typedef struct tag1{
      int a;
      struct tag2{
          long b;
      }var1;
}var2;

typedef struct {
    var2 s1;
    var2 s2;
}S;

In main:

 S x = {0};

  x.s1.a = 1;
  x.s1.var1.b = 2;
  x.s2.a = 3;
  x.s2.var1.b = 4;

Memory for struct S depicted on first line of image:

enter image description here

Note there is no additional memory usage required directly due to the struct or even sub-struct constructs. But indirectly, there can be (and often will be) additional memory required for alignment padding. This occurs when data types contained in the struct definition are of differing sizes and do not align naturally along addressing boundaries. When this occurs, padding will effect the computed sizeof a struct.

You can see that the size of each instance of your original struct is 8, (16 for two instances) and because int and long both align perfectly (and are the same size) in this instance, there appears to be no padding. Iflong were replaced with long long this would no longer be the case. Padding would almost certainly be required.

To provide context for the information below, relevant data sizes on my machine (compiled for 32bit) are:

int sizeChar = sizeof(char);     //1 (always)
int sizeInt  = sizeof(int);      //4
int sizeLong = sizeof(long);     //4
int sizeLL   = sizeof(long long);//8

There will be more visible evidence of padding and the effects of pragma using a wider range of types. The following struct contains 4 data types:

 typedef struct tag1 {
      char a;
      int b;
      long c;
      long long d;
  }var1;

Using this struct definition, it is interesting to view the difference in padding caused by using pragma pack calls. On my machine, and compiling for 32bit memory mapping, here is what I see:

enter image description here

By the way, there is a discussion here covering related points in this topic.

Upvotes: 6

nalzok
nalzok

Reputation: 16157

To figure out how the nested structure is stored in memory, you can run the code below:

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

struct tag1{
    int a;
    struct tag2{
        long b;
    } var1;
} var2;

int main(void){
    printf("CHAR_BIT is\t\t\t\t%d\n", CHAR_BIT);
    puts("");
    printf("sizeof var2 is\t\t\t\t%zu\n", sizeof var2);
    printf("sizeof var2.var1 is\t\t\t%zu\n", sizeof var2.var1);
    printf("sizeof var2.var1.b is\t\t\t%zu\n", sizeof var2.var1.b);
    puts("");
    printf("offsetof(struct tag1, a) is\t\t%zu\n", offsetof(struct tag1, a));
    printf("offsetof(struct tag1, var1) is\t\t%zu\n", offsetof(struct tag1, var1));
    printf("offsetof(struct tag1, var1.b) is\t%zu\n", offsetof(struct tag1, var1.b));
    printf("offsetof(struct tag2, b) is\t\t%zu\n", offsetof(struct tag2, b));
    return 0;
}

I'm asking you to run this code on your implementation, rather than giving you an direct answer, because:

  1. sizeof T is implementation-define. What if you have sizeof (long) == 1 and CHAR_BIT == 32?
  2. There might be padding bits/bytes in a struct.
  3. Other factors. For example, the use of #pragma pack(n)

On my implementation (clang under OS X), the output is:

CHAR_BIT is             8

sizeof var2 is              16
sizeof var2.var1 is         8
sizeof var2.var1.b is           8

offsetof(struct tag1, a) is     0
offsetof(struct tag1, var1) is      8
offsetof(struct tag1, var1.b) is    8
offsetof(struct tag2, b) is     0

Well, it does not seem neat here, but it's nicely-formatted when showing up on my screen.

So (for my implementation) the memory layout of struct tag1 will be like this:

 -----------------------
|  |  |  |  |  |  |  |  | ---> int a (8 bytes are used)
 -----------------------
|  |  |  |  |  |  |  |  | ---> struct tag2 / long b (8 bytes are used)
 -----------------------

Upvotes: 0

Kumar2080
Kumar2080

Reputation: 105

How the nested structure is stored in memory?

struct tag1{
      int a;
      struct tag2{
          long b;
      }var1;
  }var2;

First of all you need to check the machine word size (i.e either 32-bit/64-bit) & on which gcc compiler is installed. Depending upon the architectures, the variables memory allocation will be varying. sizeof operator will return the variables size according to system specific.

For example(with padding) variables stored in memory

in 32-bit machines int & long both are allocating 4-bytes.

|var2.var1.b|==>0x601058

| var2.a |==>0x601054

in 64-bit machines int allocates 4-bytes & long allocates 8-bytes.

|var2.var1.b|==>0x601058

| var2.a |==>0x601050

Memory alignment of structure members is explained here Alignment in c

Upvotes: 2

Related Questions