[C language] What is structure memory alignment? How to calculate the size of the structure?

 

Table of contents

1. Structure memory alignment

Understanding of offset:​

2. Calculation of the size of the structure

2.1 In the structure, only the size calculation of common data types

2.2 Calculation of the size of the nested structure in the structure

3. Modify the default alignment number

4. Why does memory alignment exist?


This article mainly introduces the structure memory alignment and how to calculate the size.

Before learning structure memory alignment, I don’t know if you have noticed that when we have two structures with the same type and number of member variables, but the order is different, when calculating their size, their sizes are different , such as the following code:

#include<stdio.h>
struct S1
{
	char c1;
	int i;
	char c2;
};
struct S2
{
	int i;
	char c1;
	char c2;
};
int main()
{
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));
	return 0;
}

The sizes calculated by sizeof are not the same:

 Now, let's learn how to calculate the size of the structure.

1. Structure memory alignment

Struct Memory Alignment means that when the compiler allocates the memory space of the structure variable, it arranges the members of the structure according to certain rules to ensure the access efficiency of the structure and the memory alignment requirements.

Before calculating the size of the structure, we need to understand the memory alignment rules of the structure :

1. The first member is at the address whose offset is 0 from the structure variable.

2. Other member variables should be aligned to an address that is an integer multiple of a certain number (alignment number). Alignment = Compiler's default alignment and the smaller value of the member size . The default value in VS is 8 , there is no default alignment number in Linux, and the alignment number is the size of the member itself

3. The total size of the structure is an integer multiple of the maximum alignment number (each member variable has an alignment number).

4. If a structure is nested, the nested structure is aligned to an integer multiple of its own maximum alignment, and the overall size of the structure is the integer of all maximum alignments (including the alignment of the nested structure) times.


Understanding of offset:

 Use offsetof to calculate the offset of the member variable of the structure compared to the starting position of the structure

#include<stddef.h>
#include<stdio.h>
struct S1
{
	char c1;
	int i;
	char c2;
};
int main()
{
	printf("%d\n", offsetof(struct S1, c1));
	printf("%d\n", offsetof(struct S1, i));
	printf("%d\n", offsetof(struct S1, c2));
	return 0;
}

According to the offset of each member variable, we can calculate the storage location of the structure member variable in memory:

According to the analysis of the above phenomena, we found that the members of the structure are not stored continuously in memory .

If we want to know why there is wasted space, we have to continue learning according to the alignment rules of the structure.

 

2. Calculation of the size of the structure

The following explains how to calculate the size of the structure according to the memory alignment rules of the structure:

2.1 In the structure, only the size calculation of common data types

Or take this structure type as an example:

struct S1
{
	char c1;
	int i;
	char c2;
};

 

In the same way, calculate the size of the following structure:

struct S2
{
	int i;
	char c1;
	char c2;
};

 At this point, the initial question has been resolved.

In order to consolidate the knowledge learned, here is another example of calculating the size of a structure:

struct S3
{
	double d;
	char c;
	int i;
};

 

How to calculate the size when the structure contains an array?

When there are variables of array type in the structure, we only need to regard the array as multiple variables of the same type, as shown in the following figure:

 Compile the test:

2.2 Calculation of the size of the nested structure in the structure

For structures with nested structures, we need to use the fourth rule:

If a structure is nested, the nested structure is aligned to an integer multiple of its own maximum alignment, and the overall size of the structure is an integer multiple of all maximum alignments (including the alignment of the nested structure).

Calculate a try:

struct S
{
	double d1;
	char c1;
	int i;
};
struct S7
{
	char c2;
	struct S s;
	double d2;
};
int main()
{
	printf("%d\n", sizeof(struct S7));
	return 0;
}

 

3. Modify the default alignment number

We have seen the #pragma preprocessing directive before, and here we use it again to change our default alignment.

#pragma pack(8)//设置默认对齐数为8
struct S1
{
	char c1;
	int i;
	char c2;
};
#pragma pack() //取消设置的默认对齐数,还原为默认

#pragma pack(1)//设置默认对齐数为1
struct S2
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

int main()
{
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));
	return 0;
}

Output result: 

Under normal circumstances, the alignment number is set to a power of 2, and will not be set to other numbers at will.

 Conclusion: When the alignment of the structure is not suitable, we can change the default alignment by ourselves.



4. Why does memory alignment exist?

Most of the references say something like this:

1. Platform reason (transplant reason):

Not all hardware platforms can access arbitrary data at any address; some hardware platforms can only fetch certain types of data at certain addresses, otherwise a hardware exception is thrown.

2. Performance reasons:

Data structures (especially stacks) should be aligned on natural boundaries as much as possible. The reason is that to access unaligned memory, the processor needs to make two memory accesses; while aligned memory accesses require only one access.

In general: the memory alignment of the structure is the practice of exchanging space for time

expand: 

        Struct Memory Alignment means that when the compiler allocates the memory space of the structure variable, it arranges the members of the structure according to certain rules to ensure the access efficiency of the structure and the memory alignment requirements.

In a computer, the speed at which memory can be accessed is limited, and usually by a specific byte size. In order to improve the efficiency of memory access, many computer architectures require that the address of certain types of data in memory must be a multiple of a certain value. This specific value is usually the size of the data type or the word size of the processor.

The purpose of structure memory alignment is to meet these alignment requirements to reduce the time and cost of memory access. When the member variables of the structure are arranged according to the alignment rules, the address of each member variable can be guaranteed to be aligned, thereby improving the efficiency of memory access.

        The exact alignment rules may vary by compiler, operating system, and processor. In general, alignment rules take into account the size and alignment requirements of data types, and the order and types of structure members. The compiler will insert padding bytes (Padding Bytes) between the members of the structure to ensure that the address of each member meets the alignment requirements.

It should be noted that the memory alignment of the structure may cause the size of the structure to increase, because the padding bytes will occupy additional memory space. This increased size can affect the memory layout and memory footprint of structures, especially when nesting of structures, arrays, and file IO are involved.

        In some special cases, you can use the instructions or attributes provided by the compiler to control the memory alignment of the structure to meet specific needs.

When designing the structure, we must satisfy the alignment and save space. How to do it:

Let members who occupy a small space gather together as much as possible.

struct S1
{
 char c1;
 int i;
 char c2;
};
struct S2
{
 char c1;
 char c2;
 int i;
};

The members of the S1 and S2 types are exactly the same, but there are some differences in the size of the space occupied by S1 and S2.

Guess you like

Origin blog.csdn.net/m0_73648729/article/details/132391741