(1) What is byte alignment
If a variable occupies n Bytes, the start address of the variable must be divisible by N, that is, the start address % n = 0. For struct, the N value takes the Data Type of the member species as the largest space value.
(2) Why byte alignment?
The memory space is divided by byte. Theoretically, the access to the memory space can start from any address. However, in order to speed up access to the memory, the CPU of different architectures, it is stipulated that certain types of data can only be accessed from a specific starting position. In this way, various data types can only be stored in the memory space according to the corresponding rules, but cannot be arranged one by one.
For example, some platforms start from an even address to access the memory address. For an int type (assuming a 32-bit system), if the address is stored from an even address, in this way, the int data can be read in a read cycle, but if the address starting from the odd address is stored, two read cycles are required, the Int data can be obtained only by splicing the high and low bytes of the two read results, which significantly reduces the reading efficiency.
(3) how to align bytes
A smaller alignment of each member according to its type alignment parameter (usually the size of this type) and the specified alignment parameter (if not specified, the default value is used, in addition, the length of the structure must be an integer multiple of all alignment parameters used.
This rule is bitter. You can break it down. The first half of the sentence first obtains the alignment value and then compares it with the specified alignment value. The alignment value is obtained as follows:
1. the alignment value of the data type is: For char data, its alignment value is 1, for short data is 2, for int, long, float type, its own alignment value is 4. For the double type, its own alignment value is 8, in bytes.
2. Alignment value of the struct itself: the value with the largest alignment value among its members.
The method for obtaining the specified alignment value is as follows:
# Specify the alignment value when Pragma pack (value) is used.
If this parameter is not specified, the default value is used.
The last half of the sentence is mainly for the length of the struct, because for members of the data type, it has only one alignment parameter, its length, and the alignment parameter, that is, doubled. For a struct, it may use multiple data types. Therefore, this statement is translated into an alignment rule: the starting address of each member % alignment value = 0, if the value is not equal to 0, the byte is null until the expression is true.
In other words, for struct, the sequence in which the struct is stored in the memory can be mapped using the following rules:
(1) starting address of each member % alignment value of each member = 0. If the value is not equal to 0, the byte is null until the expression is true;
(2) The length of a struct must be an integer multiple of its own alignment values. If it is not enough, the byte is left blank.
For example:
- # Pragma pack (8)
- Struct {
- Char;
- Long B;
- };
- Struct B {
- Char;
- Struct a B;
- Long C;
- };
- Struct c {
- Char;
- Struct a B;
- Double C;
- };
- Struct d {
- Char;
- Struct a B;
- Double C;
- Int D;
- };
- Struct E {
- Char;
- Int B;
- Struct a C;
- Double D;
- };
For struct a, its own alignment value is 1 for char data, and for long data, its own alignment value is 4, the maximum alignment value of a struct is 4. The sequential steps of struct a in memory are as follows:
(1) Char A. The address range is 0x0000 ~ 0x0000. The starting address is 0x0000, which must be 0 x 0000% 1 = 0. The member bytes are aligned.
(2) Long B, the starting position of the address cannot start from 0x00001, because 0 x 0001% 4! = 0, so first fill in the Null Byte until the end of 0x00003, that is, fill in 3 bytes of Null Byte, from 0x00004 to store B, its address range is 0x00004 ~ 0x0007.
(3) At this time, all members are stored and ended. The length of the struct is 8, which is twice the alignment value of the struct itself. The conditions are met (2 ).
In this case, condition (1) and condition (2) are met. The positions of each member in struct a in the memory are: A *** B, and sizeof (struct a) = 8. (Each asterisk represents one digit, and each member represents its own position. For example, a occupies one digit and B occupies four digits)
For struct B, there is a member B of the type struct a with its own alignment value of 4. For the long type, its own alignment value is 4. therefore, the self-alignment value of struct B is 4. The sequential steps of struct B in memory are as follows:
(1) Char A. The address range is 0x0000 ~ 0x0000. The starting address is 0x0000, which must be 0 x 0000% 1 = 0. The member bytes are aligned.
(2) struct a B, the starting position of the address cannot start from 0x00001, because 0 x 0001% 4! = 0, so first fill in the Null Byte until the end of 0x00003, that is, fill in 3 bytes of Null Byte, from 0x00004 to store B, its address range is 0x00004 ~ 0x00011.
(3) For long C, the starting position of the address starts from 0x000012. Because 0 x 0012% 4 = 0, the address range is 0x00012 ~ 0x0015.
(4) At this time, all members are stored and ended. The length of the struct is 16, which is four times the alignment value of the struct itself. The conditions are met (2 ).
In this case, conditions (1) and conditions (2) are met. The positions of each member in struct B in the memory are: A *** B C, sizeof (struct c) = 24. (Each asterisk represents one digit, and each member represents its own position. For example, a occupies one digit, B occupies eight digits, and C occupies four digits)
For struct C, there is a member B of the type struct a with its own alignment value of 4. For the double type, its own alignment value is 8. therefore, the self-alignment value of struct C is 8. The sequential steps of struct C in memory are as follows:
(1) Char A. The address range is 0x0000 ~ 0x0000. The starting address is 0x0000, which must be 0 x 0000% 1 = 0. The member bytes are aligned.
(2) struct a B, the starting position of the address cannot start from 0x00001, because 0 x 0001% 4! = 0, so first fill in the Null Byte until the end of 0x00003, that is, fill in 3 bytes of Null Byte, from 0x00004 to store B, its address range is 0x00004 ~ 0x00011.
(3) Double C, the address start position cannot start from 0x000012, because 0 x 0012% 8! = 0, so first fill in the Null Byte until the end of 0x000015, that is, fill in 4 bytes of Null Byte, from 0x00016 to store c, its address range is 0x00016 ~ 0x0023.
(4) At this time, all members are stored and ended. The length of the struct is 24, which is three times the alignment value of the struct itself. The conditions are met (2 ).
In this case, conditions (1) and conditions (2) are met. The positions of each member in struct C in the memory are as follows: a *** B *** C and sizeof (struct C) = 24. (Each asterisk represents one digit, and each member represents its own position. For example, a occupies one digit, B occupies eight digits, and C occupies eight digits)
For struct D, the alignment value is 8. The first three members are consistent with struct C. For the fourth member D, because 0 x 0024% 4 = 0, it can be stored from 0x0024, and its address range is 0x00024 ~ 0x00027. At this time, all members are stored and ended. The length of the struct is 28, and 28 is not a multiple of the alignment value 8 of the struct. Therefore, four spaces must be added after the struct, that is, at 0x0028 ~ Fill in four spaces on 0x0031. After completion, the struct length is 32
4 of the alignment values, meeting the condition (2 ).
In this case, condition (1) and condition (2) are met. The position of each member in struct d in the memory is a *** B *** c d ****, sizeof (struct d) = 32. (Each asterisk represents one digit, and each member represents its own position. For example, a occupies one digit, B occupies eight places, C occupies eight places, and D occupies four places ).
For each struct e member's position in the memory: A *** B c d, sizeof (struct e) = 24. (Each asterisk represents one digit, and each member represents its own position. For example, a occupies one digit, B occupies four places, C occupies eight places, and D occupies eight places ).
It can be seen from the struct D and struct e that when the number and type of members are the same, the latter occupies less space than the former because the latter has fewer empty bytes. If we consider saving space during programming, we should follow the principle of declaring variables according to the type size from small to large, so as to minimize the space to fill. In addition, you can insert a reserved member in a place that fills in NULL bytes. For example
Struct
{
Char;
Char reserved [3];
Int B;
};
The main purpose of doing so is to give a prompt to the programmer. If it is not added, the compiler will automatically complete it.
Reference:
[1] http://blog.ednchina.com/sealove518/55803/message.aspx