One, what is byte-aligned
the memory space in the computer is divided by byte, and theoretically it seems that access to any type of variable can start at any address, But the reality is that when accessing a particular type of variable, it is often accessed at a specific memory address, which requires that all types of data be arranged in space according to a certain rule, rather than one after another in order, which is alignment.
second, the role and cause of the justification:
1, Platform reason (migration reason): Not all hardware platforms can access arbitrary data on arbitrary addresses, and some hardware platforms can only fetch certain types of data at certain addresses, or throw hardware exceptions. Each hardware platform has a great difference in the processing of storage space. Some platforms have access to certain types of data only from certain addresses. For example, some of the architecture of the CPU to access a variable without alignment, the error occurs, then in this architecture programming must ensure byte alignment.
2, performance reasons: The most common is the loss of access efficiency if the data is not aligned according to its platform requirements. Data structures (especially stacks) should be aligned as far as possible on natural boundaries. The reason is that in order to access the misaligned memory, the processor requires two memory access, while the aligned memory access requires only one access. For example, some platforms start every time from the even address, if an int (assuming 32-bit system) if stored in the beginning of the even address, then a read cycle can read out the 32bit, and if the location of the beginning of the odd address, it will take 2 reading cycles, The 32bit data can be obtained by piecing together the high and low byte of the results of two readings. Obviously, the reading efficiency is much lower.
Three, align rules
each compiler on a particular platform has its own default alignment factor (also called the Zimo number). Programmers can change this coefficient by precompiling the command #pragma pack (n), where n is the "alignment factor" you want to specify.
rule:
1, data member alignment rule: struct (struct) (or union) data member, first data member where offset is 0, The alignment of each data member in the future is performed according to the value specified by the #pragma pack and the length of the data member itself, smaller than that. The overall alignment rule for
2, struct (or union): After the data member completes its own alignment, the structure (or union) itself is aligned, and the alignment will be in the value and structure (or union) of the maximum data member length specified by the #pragma pack. The smaller one is.
3, when the n value of the #pragma pack equals or exceeds the length of all data members, the size of this n value will have no effect.
Please see the following structure:
struct MYSTRUCT
{
Double dda1;
Char DDA;
int type
};
What will happen to the structure mystruct adoption sizeof? How much is sizeof (MYSTRUCT)? Perhaps you would ask: sizeof (MYSTRUCT) =sizeof (double) +sizeof (char) +sizeof (int) =13
But when you test the size of the above structure in VC, you will find that sizeof (MYSTRUCT) is 16. Do you know why the VC will come up with such a result?
In fact, this is a VC for variable storage of a special treatment. In order to improve the CPU storage speed, VC for some variables to start the address of the "alignment" processing. By default, VC stipulates that the offset of the starting address of each member variable in relation to the starting address of the structure must be a multiple of the number of bytes occupied by the type of the variable. The common types of alignment (vc6.0,32 bit systems) are listed below.
Type alignment (the offset at which the variable holds the starting address relative to the structure's starting address)
Char offset must be a multiple of sizeof (char) or 1
The int offset must be a multiple of sizeof (int), or 4
Float offset must be a multiple of sizeof (float) or 4
Double offset must be sizeof (double) that is a multiple of 8
The short offset must be a sizeof (short) that is a multiple of 2
Each member variable at the time of storage according to the order in the structure of the application space, in accordance with the above alignment adjustment position, the blank byte VC will automatically fill. At the same time VC to ensure that the size of the structure of the structure of the number of bytes (that is, the structure of the maximum space occupied by the type of the number of bytes) multiples, so after the last member variable request space, will also automatically fill the blank bytes as needed.
The following examples to illustrate how the VC to store the structure.
struct MYSTRUCT
{
Double dda1;
Char DDA;
int type
};
When allocating space for the above structure, VC allocates space for the first member DDA1, based on the order and alignment of the member variable, and the starting address is the same as the starting address of the structure (just offset 0 is just a multiple of sizeof (double)), The member variable occupies sizeof (double) = 8 bytes; Then allocates space for the second member, DDA, at which point the next address that can be allocated is 8 for the start address of the struct, and is a multiple of sizeof (char). So the DDA is stored in an offset of 8, where the alignment is satisfied, the member variable occupies sizeof (char) = 1 bytes; then allocates space for the third member type, at which point the next address that can be allocated is 9 for the starting address of the struct, not sizeof (int) = Multiples of 4, in order to meet the alignment of the offset constraint problem, VC automatically fill 3 bytes (these three bytes do not put anything), then the next can be assigned to the address of the structure of the starting address of the offset of 12, just sizeof (int) =4 multiples, So the type is stored at an offset of 12, which occupies the sizeof (int) = 4 bytes, at which point the entire structure's member variables are already allocated space, and the total amount of space occupied is: 8+1+3+4= 16, just a multiple of the number of bytes in the structure (that is, the number of bytes in the structure that occupies the maximum space sizeof (double) =8), so there is no vacant byte that needs to be populated. So the size of the entire structure is: sizeof (mystruct) =8+1+ 3+4=16, of which 3 bytes are automatically filled with VC, without any meaningful things.
Let's take another example and swap the position of the MYSTRUCT member variable above to make it the following:
struct MYSTRUCT
{
Char DDA;
Double dda1;
int type
};
How much space does this structure occupy? In the VC6.0 environment, sizeof (MYSTRUC) can be obtained as 24. In combination with some of the principles of allocation space mentioned above, this paper analyzes how VC allocates space for the above structure. (Simple description)
struct MYSTRUCT
{
The Char dda;//offset is 0, the alignment is satisfied, and the DDA occupies 1 bytes;
Double dda1;//The offset of the next available address is 1, not a multiple of the sizeof (double) =8, which requires 7 bytes to be offset to 8 (the alignment is satisfied), so the VC automatically fills 7 bytes, and the dda1 is placed on the address with an offset of 8, It occupies 8 bytes.
int type;//The offset of the next available address is 16, which is a multiple of the sizeof (int) =4, which satisfies the alignment of the int, so no VC autofill is required, and type is placed on an address with an offset of 16, which occupies 4 bytes.
};
All member variables are allocated space, the total size of the space is 1+7+8+4=20, not the number of section boundaries of the structure (that is, the number of bytes in the structure occupied by the maximum space sizeof (double) =8), so you need to populate 4 bytes, To meet the size of the structure as a multiple of the sizeof (double) =8. So the total size of the structure is: sizeof (MYSTRUC) is 1+7+8+4+4=24. One of the total 7+4=11 byte is automatically filled with VC, did not put any meaningful things.
The special handling of the storage of the structure of VC does increase the speed of the CPU storage variable, but sometimes it also brings some trouble, we also shield off the default alignment of the variable, we can set the alignment of the variable. VC provides the #pragma pack (n) to set the variable in n-byte alignment. N-byte alignment means that the offset of the starting address of the variable is stored in two ways: first, if n is greater than or equal to the number of bytes occupied by the variable, the offset must meet the default alignment, and secondly, if N is less than the number of bytes used for the variable's type, the offset is a multiple of n, not the default alignment. The total size of the structure also has a constraint, in the following two cases: if n is greater than the number of bytes occupied by all member variable types, the total size of the structure must be a multiple of the space occupied by the most space-consuming variable, otherwise it must be a multiple of n.
The following examples illustrate its use.
#pragma pack (push)//Save alignment status
#pragma pack (4)//set to 4-byte alignment
struct test
{
Char M1;
Double M4;
int m3;
};
#pragma pack (POP)//restore alignment status
The size of the above structure is 16, the following analysis of its storage, first for the M1 allocation of space, its offset is 0, to meet our own set alignment (4-byte alignment), M1 occupies 1 bytes. It then starts allocating space for the M4, with an offset of 1, which needs to complement 3 bytes, so that the offset is a multiple of n=4 (because sizeof (double) is greater than N), and M4 occupies 8 bytes. The space is then allocated for the M3, with an offset of 12, a multiple of 4, and a M3 of 4 bytes. Space has been allocated for all member variables and 16 bytes have been allocated, which satisfies a multiple of n. If the above #pragma pack (4) is changed to #pragma pack (16), then we can get the size of the structure to be 24. (Please let the reader analyze yourself)
Five, look at the following example
Copy Code code as follows:
#pragma packs (8)
struct S1
{
Char A;
Long B;
};
struct S2
{
char c;
struct S1 D;
Long long E;
};
#pragma pack (POP)
sizeof (S2) results are 24. There is an important condition for member alignment, that is, each member is aligned separately. That is, each member is aligned in its own way. This means that although the above specifies a 8-byte alignment, not all members are aligned in 8 bytes. The rule for its alignment is that each member is aligned to the smaller of its type's alignment parameters (usually the size of this type) and the specified alignment parameter (here is 8 bytes). And the length of the structure must be an integer multiple of all the alignment parameters used, not enough to fill the byte.
In S1, member A is 1 bytes by default by 1-byte alignment, specifies that the alignment parameter is 8, the values are 1,a by 1 bytes, member B is 4 bytes, the default is 4-byte alignment, then the 4 byte is aligned, so sizeof (S1) should be 8;
In S2, like a in C and S1, 1-byte alignment, and D is a struct, which is 8 bytes, and what does it align? For a struct, its default alignment is the largest of the alignment parameters used by all its members, and the S1 is 4. Therefore, member D is aligned by 4 bytes. Member E is 8 bytes, it is the default 8-byte alignment, as specified, so it is on the 8-byte boundary, at which time, 12 bytes have been used, so the addition of 4 bytes of space, starting from the 16th byte to drop member E. At this point, the length is 24, Can already be divisible by 8 (Member E in 8-byte alignment). In this way, 24 bytes were used altogether.
A b
S1 Memory layout: 11**,1111,
C s1.a s1.b D
S2 Memory Layout: 1***,11**,1111,****11111111
Here are three important points:
1. Each member is aligned in its own way and can minimize length.
2. The default alignment of a complex type, such as a struct, is the alignment of its longest member, so that the length can be minimized when the member is a complex type.
3. The length of the alignment must be an integer multiple of the largest alignment parameter in the member, so that each entry is guaranteed to be aligned when the array is processed.
Vi. sizeof Examples (Note: The following examples are tested and validated)
Copy Code code as follows:
Std::cout << "void* size" <<sizeof (void*) <<std::endl; 4
Std::cout << "char size" <<sizeof (char) <<std::endl; 1
Std::cout << "unsigned char size" <<sizeof (unsigned char) <<std::endl; 1
Std::cout << ' short Size ' <<sizeof (short) <<std::endl; 2
Std::cout << "int size" <<sizeof (int) <<STD::ENDL;//4
Std::cout << "unsigned int size" <<sizeof (unsigned int) <<std::endl; 4
Std::cout << "Long Size" <<sizeof (long) <<std::endl; 4
Std::cout << "long int size" <<sizeof (long int) <<std::endl; 4
Std::cout << "Long Long Size" <<sizeof (long Long) <<std::endl; 8
Std::cout << "Float size" <<sizeof (float) <<std::endl; 4
Std::cout << "Double size" <<sizeof (double) <<std::endl; 8
Std::cout << "time_t size" <<sizeof (time_t) <<STD::ENDL;//8
Char bufc[32];
Std::cout << "BUFC size" <<sizeof (BUFC) <<std::endl;//32
struct teststruct{};
Class testclass{};
Std::cout << "struct size" <<sizeof (teststruct) <<STD::ENDL;//1
Std::cout << "Class size" <<sizeof (TestClass) <<STD::ENDL;//1
Class A
{
char c;
int Val;
Short sh;
};
Class B
{
Public
char c;
int Val;
Short sh;
void Func1 (void) {};
virtual void Func2 (void) {};
};
Std::cout << "class size A" <<sizeof (a) <<STD::ENDL;//12
Std::cout << "class size B" <<sizeof (b) <<std::endl;//16
Char*p =null;
P=new char[100];
Std::cout << "Size P" <<sizeof (p) <<STD::ENDL;//4
Vii. Other
1, in the code can be written through the #pragma pack (n), n=1,2,4,8,16 to flexibly control the coefficient of memory alignment, when you need to turn off the memory alignment, you can use the #pragma pack () implementation.
2. Attention matters
Memory alignment can greatly improve the processing speed of the compiler, but not all the time is necessary, sometimes do not pay attention to, there may be unexpected mistakes! The most typical case is the code of the network communication program,
It is important to use the #pragma pack () to shut down the memory before defining the struct or union, because the remote host usually does not know what alignment the other uses, the byte stream that is received through the socket, and then parses by bytes
The corresponding results, if the use of memory alignment, the remote host is likely to get the wrong result! This situation has been the guidance on the machine encountered, and belong to a more covert error, debug a long time to find out the problem here.
3, optimize the structure body
While memory alignment can improve operational efficiency, but it wastes memory, it usually doesn't care about small space on modern PCs, but in some small memory embedded devices, it may be a penny-pinching. In fact, we found that without affecting the functionality of the premise, you can adjust the order of members to reduce the "memory hole" of waste.