Understanding Memory Alignment of C Structs in Embedded Systems

Today, I bring you a classic and commonly mistaken question about memory alignment of C language structures:

Calculate the number of bytes occupied by the following structure in a 32-bit environment:
typedef struct test_struct
{
 char a;  
 short b;     
 char c;     
 int d;
 char e;
}test_struct;

Please provide your answer:

Understanding Memory Alignment of C Structs in Embedded Systems

Let’s take a look at the actual test situation:

1. Test Code:

/***********************************
 * Official Account: Embedded Miscellaneous
***********************************/
#include <stdio.h>

typedef struct test_struct
{
 char a;  
 short b;     
 char c;     
 int d;
 char e;
}test_struct;

int main(void)
{
 test_struct test_s;  

 printf("\n============================================\n");
 printf("test_s addr   = %#.8x\n", &test_s);
 printf("test_s.a addr = %#.8x\n", &test_s.a);
 printf("test_s.b addr = %#.8x\n", &test_s.b);
 printf("test_s.c addr = %#.8x\n", &test_s.c);
 printf("test_s.d addr = %#.8x\n", &test_s.d);
 printf("test_s.e addr = %#.8x\n", &test_s.e);
 printf("sizeof(test_s) = %d\n", sizeof(test_s));
 printf("============================================\n");

 return 0;
}

2. Running Result

Understanding Memory Alignment of C Structs in Embedded Systems

In a 32-bit environment, the number of bytes occupied by this structure is 16. Did you get it right?

The output of the running results printed many important pieces of information, and the analysis should be quite clear from the results, right?

Now, let’s analyze it together.

3. Analysis

Before analyzing this problem, let’s remember three principles about structure memory alignment:

(1) The starting address of the structure variable must be divisible by the size of its widest member.

(2) Each member of the structure must have an offset from the starting address that is divisible by its own size; if not, padding bytes are added after the previous member.

(3) The total size of the structure must be divisible by the size of the widest member; if not, padding bytes are added at the end.

In analyzing this problem, we will not consider the case where the compiler can specify the alignment size. In a 32-bit environment, the default alignment size is generally 4.

Now, let’s analyze according to these three principles and derive the following diagram:

Understanding Memory Alignment of C Structs in Embedded Systems

From this diagram, we should be able to clearly see the memory usage of the entire structure variable.

If you still can’t understand it, you can read the explanation below (it’s a bit verbose, if you’ve understood it, you don’t need to read it~):

From the results of the above example, the starting address of our structure variable test_s is 0x0028ff30, which is divisible by the size of its widest member (the int type member d, which occupies 4 bytes), conforming to principle (1).

The address of member a is the starting address of the structure variable 0x0028ff30, and following a is the member b of type short (two bytes).

According to rule (2), it is clear that the address of b cannot start from 0x0028ff31, so the compiler will add 1 padding byte after the previous member (a member), so the address of b will be from 0x0028ff32, which conforms to rule (2).

Member b occupies two bytes, and the address after two bytes is 0x0028ff34, while member c is of type char (1 byte), so according to rule (2), member c will be stored at address 0x0028ff34.

Member c occupies 1 byte, and the address after 1 byte is 0x0028ff35, while following c is member d of type int (4 bytes), which clearly does not satisfy rule (2).

The compiler will fill 3 bytes after the previous member (c member) to satisfy rule (2), and at this point d will be stored at address 0x0028ff38.

Member d occupies 4 bytes, and the address after 4 bytes is 0x0028ff3c. According to rule (2), member e can start to be stored from this address.

At this point, a + padding byte + b + c + padding byte + d + e occupies a total of 13 bytes, while the size of the widest member of the structure (the int type member d) occupies 4 bytes.

Clearly, this does not satisfy rule (3), and the compiler will add 3 bytes of padding after member e. Therefore, the total number of bytes occupied by the entire structure variable test_s is 16 bytes.

4. Practical Applications

(1) Use reserved variables to replace padding bytes

In practical applications, we can change the above structure variable to:
typedef struct test_struct
{
 char a;  
 char reserve0;    /* Reserved member */
 short b;     
 char c;     
 int d;
 char e;
 char reserve1[3]; /* Reserved member */
}test_struct;
We already know that the compiler will automatically add some padding bytes to our structure variable, and these padding bytes are invisible to us; they are implicit.

In cases where the structure variable occupies the same memory, we can explicitly represent these padding bytes by creating some reserved members.

This way, when we need to add some members to this structure, we can replace the reserved members with actual members. This can help us save memory space to some extent.

(2) Adjust the positions of structure members

From the analysis above, we know that the compiler will add padding bytes based on the arrangement of our structure members to achieve alignment.

Therefore, if we manually align some members, we can save some space. For example, if we change the order of our test_struct structure members to:

typedef struct test_struct
{
 char a;  
 char c; 
 short b;         
 int d;
 char e;
}test_struct;

Then the number of bytes occupied by the structure variable test_s becomes 12 bytes, that is:

Understanding Memory Alignment of C Structs in Embedded Systems

This saves 4 bytes compared to the original 16 bytes.

Although this optimization may not be necessary for general embedded applications, if one day we really need to develop applications in resource-constrained embedded devices, this is a point that can be optimized.

This concludes today’s sharing. If you have any original articles related to electronic design or other related technical topics, feel free to submit them to us. We will select the best ones, and publishing articles will earn you a reward!
Understanding Memory Alignment of C Structs in Embedded Systems
Kind Reminder:

Due to recent changes in the WeChat public platform’s push rules, many readers have reported not seeing updated articles in a timely manner. According to the latest rules, it is recommended to click on “Recommended Reading, Share, Collect” more often to become a regular reader.

Recommended Reading:

  • Zhi Hui Jun is up to big things again!

  • All employees are dismissed! Shenzhen’s 30-year electronics giant announces shutdown.

  • The shocking insider about “illegal dismissal of employees by female executives”: using pirated EDA, the chip coverage rate is over 20% and they dare to tape out!!

Please click 【To Watch】 to give the editor a thumbs up

Understanding Memory Alignment of C Structs in Embedded Systems

Leave a Comment

×