First, let's take a look at some of the fundamentals:
One, what is byte alignment
When a variable of a primitive type occupies n bytes in memory, the starting address of the variable must be divisible by n, that is, the variable is byte-aligned, and for a struct, a union, that N takes the largest number of bytes of space in its members of all its basic types;
Memory space is divided in bytes as basic units, in theory, it seems that access to any type of variable can start from any address, but the reality is that when accessing a particular type of variable is often from a specific memory address to start Access, This requires that the various types of data can only be arranged spatially in accordance with certain rules, rather than being discharged one by one; The reason is that in order to enable CPUs of different architectures to increase the speed of accessing memory, it is stipulated that for certain types of data can only be accessed from a specific memory location; All types of data can only be discharged in memory space according to the corresponding rules, but not sequentially, continuously, one by one; this is the memory alignment;
Second, why byte alignment is required
Because of the various hardware platform to the storage space processing is very different; some platforms can only access certain types of data from a specific memory address, such as: Some architectures of the CPU to access a non-aligned variable when the error occurs, then programming in this framework must ensure that byte alignment; Other platforms may not have this, but most often, if the data is not aligned according to its platform requirements, it will result in a loss of access efficiency, for example, some platforms each read the data from an even address at the beginning, if an int (assuming that the 32-bit system) data from the location of the store, Then only a read instruction period can be completely read out of the 32bit int data, conversely, if this 32bit int data is stored from the odd address, then it takes two read instruction period to fully read the 32bit int data, It is also necessary to re-assemble the high and low bytes of the two read results to get the correct 32bit data; At this time, the efficiency of CPU reading is obviously decreased;
Three, byte alignment rules
the preprocessing instruction #pragma pack (Align_value) is used to specify the alignment value, while the preprocessing instruction #pragma pack () is used to cancel the last set alignment value and restore the default alignment value;
byte alignment is for basic type variables: char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, Unsigned long long, float, double, and so on; therefore, the alignment of a struct can only be aligned according to the basic type of its member variables;
There are four concepts to understand:
A, the alignment value of the data type itself :
is the size (in units, bytes) of the operation of the data type using the sizeof () operator, for example, for data of type [unsigned] char, with its own alignment value of 1 bytes, and for data of [unsigned] short type, Its own alignment value is 2 bytes, for [unsigned] int, [unsigned] long, [unsigned] long long, float, double and other data types, its own alignment value is 4 bytes;
The self-aligning values of B, struct, union, class :
is the value that is the largest of the members of all its basic types, and if there are variables of nested or compound types in these composite types, then the variables of these nested types or compound types need to be disassembled into the members of the base type and then aligned;
C, specify the alignment value :
refers to the alignment value Align_value specified using the preprocessing directive #pragma pack (align_value);
D, valid alignment values for data members, structs, and classes :
is the smaller value of its own alignment value and the specified alignment value;
where the effective alignment value is the value that ultimately determines the way the data is stored, the most important thing is to set a valid alignment value of n, which means "align on n bytes", that is, "store the starting address%n=0" for that data;
Therefore, a valid alignment value for each type of data is its own alignment value (usually the size of this type) and the smaller value in the specified alignment value (which does not specify the default value), and the struct itself alignment value is the highest value of its own alignment value in all its members;
The details of byte alignment are related to the implementation of the compiler, but in general, the structure needs to meet several guidelines :
1). From the outside of the structure, the first address of a struct variable is divisible by the size of its widest base member; from the inside of the struct, its first data member has an offset of 0 relative to the first address of the entire struct, that is, the first data member of the struct is stored at an offset of 0;
2). The valid alignment value for each data member in the struct takes its own alignment value and the smaller one in the specified alignment value; Alternatively, the offset of each data member in the struct relative to the first address of the struct is an integer multiple of that data member size and the smaller value (or valid alignment value) of the specified alignment value. If necessary, the compiler adds padding bytes between data members;
3). If there are nested structures or struct variables in the structure, then the nested structures or struct variables must be split into basic type members, and the alignment of the longest basic type members is taken.
4). The effective alignment value of the structure as a whole must be an integer multiple of its widest base type member size, or, in other words, the overall size of the struct is an integer multiple of the size of the widest base type member in the struct, and if necessary, the compiler adds padding bytes after the last member; The effective alignment values for the whole structure are based on the size of the widest base type member in the struct and the smaller value in the specified alignment value;
Special NOTE: If you specify that the alignment value is greater than its own alignment value, the specified alignment value is not valid;
Then, let's take a look at the C compiler's handling of byte alignment
By Default, the C compiler allocates space for each variable or data unit according to its natural boundary conditions.
in structs, the compiler allocates space for each member of the structure according to its natural bounded (alignment) condition. Each member is stored sequentially in memory in the order in which they are declared (there may be empty bytes inserted between the members), and the address of the first member is the same as the address of the entire structure.
The default struct member of the C compiler has a natural boundary condition of "N-byte alignment", and n is the length of the member data type. the natural boundary condition for a member of type int is 4-byte aligned, while the natural-bound condition of a struct member of a double type is 8-byte aligned. If the member's starting offset is not on the member's default natural bound condition, add an appropriate number of empty bytes after the previous section face.
The default structure of the C compiler is the natural boundary condition of the whole: the maximum natural-bound condition required by all members of the struct. if the sum of the length of each member of the structure is not the integer multiple of the whole natural boundary condition of the structure, then the empty byte is filled after the last member.
Example 1 (the default byte-to-boundary condition for the default byte-to-boundary condition and structure of each member of the analysis structure):
structchar//char//float// char//};
Because the largest member of the test struct is Flaot x3, the natural boundary condition for this struct is 4-byte aligned. The struct length is 12 bytes and the memory layout is 1100 1111 1000.
Example 2:
#include <stdio.h>//#pragma pack (2)typedefstruct{ intAa1;//4-byte alignment 1111 CharBB1;//1-byte alignment 1 ShortCC1;//2-byte alignment 011 CharDD1;//1-byte alignment 1} testlength1;intLength1 =sizeof(TESTLENGTH1);//4 byte aligned, occupies byte 1111 1011 1000,length =typedefstruct{ CharBB2;//1-byte alignment 1 intAA2;//4-byte alignment 01111 ShortCC2;//2 byte alignment one CharDD2;//1-byte alignment 1} testlength2;intLength2 =sizeof(TESTLENGTH2);//4 byte aligned, takes up bytes 1111 1110,length =typedefstruct{ CharBb3;//1-byte alignment 1 CharDD3;//1-byte alignment 1 intAa3;//4-byte alignment 001111 ShortCc23//2 byte alignment one} testlength3;intLength3 =sizeof(TESTLENGTH3);//4 byte aligned, occupies byte 1100 1111 1100,length =typedefstruct{ CharBb4;//1-byte alignment 1 CharDD4;//1-byte alignment 1 ShortCC4;//2 byte alignment one intAA4;//4-byte alignment 1111} Testlength4;intLength4 =sizeof(TESTLENGTH4);//4 byte aligned, occupies byte 1111 1111,length = 8intMainvoid) {printf ("length1 =%d.\n", length1); printf ("length2 =%d.\n", length2); printf ("length3 =%d.\n", LENGTH3); printf ("Length4 =%d.\n", Length4); return 0;}
Change the default boundary condition (Specify the bounds)
· Using the pseudo-directive #pragma pack (n), the C compiler will be aligned in N bytes.
· Use pseudo-Directives #pragma pack () to cancel custom byte alignment.
At this point, the alignment rule is:
1.data member Alignment rules: data members of a struct (struct) (or union), the first data member placed at offset 0, and subsequent alignment of each data member according to the value specified by the #pragma pack and the length of the data member itself, The relatively small one is carried out.
2, structure (or union) of the overall alignment rules: After the data members have completed their respective alignment, the structure (or union) itself will be aligned, alignment will follow the value specified by the #pragma pack and the structure (or union) of the maximum data member length, the smaller one.
In conjunction with 1, 2 inference: When the n value of the #pragma pack equals or exceeds the length of all data members, the size of the N value will have no effect.
Therefore, when the pseudo-directive #pragma pack (2) is used, the size of the test struct is 8 and the memory layout is 11 11 11 10.
It is important to note that when a struct contains a sub-struct, the members in the substructure are aligned with the value specified by the #pragma pack and the maximum data member length of the substructure, which is smaller than the lower one.
Example 3:
#pragma Pack (8)struct s1{ short A; Long b;}; struct s2{char c;s1 D; Long Long e;}; #pragma pack ()
The result of sizeof (S2) is 24. The memory layout of the S1 is 1100 1111,s2 memory layout is 1000 1100 1111 0000 1111 1111.
Example 4:
#include <stdio.h>#pragmaPack (2)typedefstruct{ intAa1;//2-byte alignment 1111 CharBB1;//1-byte alignment 1 ShortCC1;//2-byte alignment 011 CharDD1;//1-byte alignment 1} testlength1;intLength1 =sizeof(TESTLENGTH1);//2 byte aligned, takes up bytes one by one 10,length = Tentypedefstruct{ CharBB2;//1-byte alignment 1 intAA2;//2-byte alignment 01111 ShortCC2;//2 byte alignment one CharDD2;//1-byte alignment 1} testlength2;intLength2 =sizeof(TESTLENGTH2);//2 byte aligned, takes up bytes by one by one 10,length = Tentypedefstruct{ CharBb3;//1-byte alignment 1 CharDD3;//1-byte alignment 1 intAa3;//2 byte aligned one ShortCc23//2 byte alignment one} testlength3;intLength3 =sizeof(TESTLENGTH3);//2 byte alignment, takes up bytes one by one 11,length = 8typedefstruct{ CharBb4;//1-byte alignment 1 CharDD4;//1-byte alignment 1 ShortCC4;//2 byte alignment one intAA4;//2 byte aligned one} Testlength4;intLength4 =sizeof(TESTLENGTH4);//2 byte alignment, takes up bytes one by one 11,length = 8intMainvoid) {printf ("length1 =%d.\n", length1); printf ("length2 =%d.\n", length2); printf ("length3 =%d.\n", LENGTH3); printf ("Length4 =%d.\n", Length4); return 0;}
In addition, there are one of the following ways:
· __attribute ((aligned (n))) that aligns the members of the structure to the N-byte natural boundary. If the length of a member in the structure is greater than n, the length of the maximum member is aligned.
· __ATTRIBUTE__ ((packed)), cancels the optimization alignment of the structure during compilation, aligned according to the actual number of bytes consumed.
Above n = 1, 2, 4, 8, 16 ... The first approach is more common.
byte-to-align and its related processing in C language