C + + memory alignment reprint

Source: Internet
Author: User

Reprinted from http://blog.csdn.net/chengonghao/article/details/51674166

Examples are particularly good

Many articles probably have a conclusion like this:

1. Data items can only be stored in memory locations where the address is an integer multiple of the size of the data item;

2. The first address of a struct variable can be divisible by the size of its widest base type member;

3. Align on N, meaning that the data "holds the starting address%n=0

Obviously, if the data storage address is wrong, then the inferred address alignment rules are all wrong, and in fact, the same is true. I study this topic 80% of the time is spent on this, and the real alignment rules should be resolved in the afternoon.

Of course, a conclusion like the one above is basically correct in general, that is to say:

The address of the char variable is%1 = 0;

Short variable address%2 = 0;

The address of the int variable is%4 = 0;

The address of the double variable%8 =0

This assumes:

sizeof (char) = 1;

sizeof (short) = 2;

sizeof (int) = 4;

sizeof (double) =8

This is the actual value on the Win32 platform, which is based on this assumption.

It should be correct when these variables are in the data area of memory (or read-only data area) or allocated from the heap, because the compiler and heap management may help you do this very well, and the programmer in the code basically can't control the start address of the variables in these areas, In fact, many of my actual tests also conform to the above conclusion, that is, the variable holds the starting address%n=0, the structure is also consistent with the first address can be the size of its widest base type is divisible.

And the only thing that we are more flexible to control is the data on the stack, which is the local variable. On a 32-bit system stack The unit size is the three bit, that is 4 bytes, each stack address must also be%4 = 0, if a stack is stored char/short/int then they must also meet% N = 0. The only thing we can find is the use of a 8-byte data, double, by the clever arrangement of the data on the stack so that the address of the double variable can be divisible by 4 and not divisible by 8 of the address, then our goal is achieved, "storage start address% N = 0" Conclusion can be Overthrow. Of course, familiar with the stack layout, these can be easily done. Specifically, you can experiment with the following steps.

#include"stdafx.h"    int_tmain (intARGC, _tchar*argv[]) {        DoubleA =0; Doubleb =0; Doublec =0; printf ("&a=0x%x, &b=0x%x, &c=0x%x", &a, &b, &c);      GetChar (); return 0; }  

The following is the output on the VS2013

As you can see, the last digit of the variable address is 4 and cannot be divisible by 8 (Double is 8 bytes), so you can already overturn the conclusion 1.

These addresses may be somewhat random, depending on the environment and the compilation parameters, but, in any case, what we actually see can already overturn the conclusion of the above conclusion 1 error on the address hypothesis. Let's take a look at the structure and completely overthrow them! In order for a variable of the internal type to be aligned according to its own alignment parameters, we specify that the alignment parameter is set to 16.

#include"stdafx.h"    #pragmaPack (16)structa{CharA; Doubleb;        }; int_tmain (intARGC, _tchar*argv[]) {        structA; structA B; structA C; printf ("&a=0x%x, &b=0x%x, &c=0x%x\n", &a, &b, &c); printf ("&a.b=0x%x, &b.b=0x%x, &c.b=0x%x", &A.B, &b.b, &c.b);      GetChar (); return 1; }  

As can be seen above, the maximum length member of struct A is of type double, that is, member variable B. As you can see, the starting address of a struct variable cannot be divisible by 8, and the address of a double member in a struct cannot be divisible by 8, and the reason for this is that the starting address of a struct variable cannot be divisible by 8, resulting in a double member being divisible by 8.

What we actually see has been able to overturn the conclusions of the above conclusion 2 on the wrong assumption of the address.

Although there will be different values in different compilation environments and systems, from the above two experiments we do get values that do not satisfy those conclusions, that is to say, the assumptions and conclusions of the starting address of the variable must be wrong!

I thought I was more familiar with the stack layout, through a number of tests are not can be fully predicted, but later proved that all is futile, in different compilation environment, especially the compiler optimization options, stack storage is simply a variety of, the basic prediction is not, we really can not make too many assumptions about the address of the variable.

2. Byte alignment rules for addresses

The rules for address alignment are also not very complex, as long as you change the assumptions about the starting address a little bit, it's pretty much the same. Here I first give a summary of my own version, and then slowly argument and analysis.

The compiler has a specified alignment parameter for structure, union, and class members, the compiler on the Win32 platform is default to 8, and the specified alignment parameter can be specified in the code using the Pack (N) directive, and the value of the N legal is 1,2,4,8,16.

Each internal type itself also has its own alignment parameters, in general this alignment parameter is sizeof (specific type) value, on the Win32 platform is the use of sizeof as the specific type of self-aligning parameters, that is, Char's own alignment parameter is 1, short is 2 , int is 4, float is 4, double is 8, etc.

Address alignment is relative to the members of a struct, and a single internal type of variable has no justification for misalignment.

The members of a struct are discharged sequentially in the order in which they are declared in the structure, which means the relative alignment of the member relative to the starting address of the struct variable, and the key is the offset from the starting address of the structure variable.

Valid alignment parameters, the valid alignment of an inner type refers to its own alignment parameter and the smaller alignment parameter in the specified alignment parameter; a valid alignment parameter for a struct type is the value that is the largest of the valid alignment parameters in its members. The effective alignment of an array is the valid alignment of its member type.

With this we can draw the rules of alignment:

1. (Offset of the starting address of the member relative to the start address of the structure)% (valid alignment of the member) = = 0

2. (Total size of the structure)% (effective alignment of the structure) = = 0

3. If the alignment rule cannot be satisfied, fill the byte until the alignment rule is satisfied

As can be seen from the above, if the specified alignment parameter is greater than the variable's own alignment parameters, the specified alignment parameters will not work, which is why #pragma pack (16) for the reason, so that the specified alignment parameters are useless, the individual variables according to their own type of alignment parameters aligned.

The total size of the structure is also required to conform to the rules, mainly considering the case of the structure of the array, the members of the array are tightly arranged, there will be no voids, if the total size of the structure satisfies the alignment requirements, then the entire array will naturally meet the alignment requirements, if the total size does not meet the alignment requirements, Each member of the array is also tightly aligned, so this alignment is meaningless, and the CPU spends extra overhead reading the array members.

Having said so much, I still give an example to speak.

# pragma pack (+)  struct  a{        char  A;         Double b;  };  

The address of the first member is the starting address of the structure, so its address is offset from the start address of the struct is 0, and a is a char type, its own alignment is 1 less than the specified alignment parameter 16, so a valid alignment is 1,a's start address offset also satisfies 0 1 = 0; the second member is D The ouble type, whose own alignment parameter is 8, is less than the specified alignment parameter, so its valid alignment is 8, so that the # pragma pack (16) We specify is the equivalent of a bit of useless. For a double type member B to satisfy the alignment rule, the byte must be padded behind a so that the address of B is at least 8 offset from the start address of the struct. So the memory layout of structure A would be like this:

xx xx xx xx xx xx xx xx xx    

and sizeof (A) = 16;0 The position of A and B respectively, and CC is the 7 bytes of padding.

    1. # pragma pack (16)
    2. struct a{
    3. Char A;
    4. Short C;
    5. double b;
    6. };



The same alignment parameter specified still does not have any effect, a or at the address offset 0, c after a, C, the effective alignment is self-aligning 2, at the relative start address offset to 2 address, to meet the alignment requirements 2 2 = 0,c and A are filled with 1 bytes. B is still on an address with an offset address of 8, and 4 bytes are populated between B and C. The memory layout of structure A is as follows:

# pragma pack (+)  struct  a{        char  A;          Short C;         Double b;  };  

    1. CC CCCC CC 00 00 00 00 00 00 00 00



and sizeof (A) = 16;0, respectively, represents the position of A,c,b, CC is the padding byte.

# pragma pack (+)  struct  a{        char  A;         Double b;          Short c;  };  

Specifying alignment is still useless, a at an address offset of 0, B on the address offset to 8, C is close to the bottom of B, because at this point the address offset 16 has met the C alignment requirements 16 2 = 0; So there is no need to populate the bytes. But the total size of struct A also satisfies the second rule of alignment, that is (the total size of the structure)% (the structure of the effective alignment) = = 0, and the effective alignment of the structure A is the most effective alignment of the members of the largest number, that is, the alignment parameter of B 8, so the effective alignment of a is 8, the total size of the structure to meet the alignment requirements Also 6 bytes must be populated after C. At this point A's memory layout is as follows:

xx xx xx xx xx xx xx xx xx  One  one cc cc CC CC  

sizeof (A) = 24;0 represents the position of A/b, and 1111 represents the position of C.

# pragma pack (4)  struct  a{        char  A;         Double b;          Short c;  };  

Set the specified alignment parameter to 4, at which point the valid alignment of a and C is still its own alignment, and b because its own alignment 8 is greater than the specified alignment 4, so the effective alignment of B now becomes 4 and no longer 8. A is still in the offset 0,b to satisfy the alignment rules, the address offset must be an integral multiple of its valid alignment, so the offset of B should be 4,c still closely behind B, because at this point the offset 12 satisfies the C alignment requirement 12 2 = 0; The effective alignment of structure A now becomes 4, namely equals the maximum valid alignment of the member, and the effective alignment of B. The total size of a to satisfy the alignment rules must also be padded with 2 bytes after C, making the total size 16 bytes. At this point A's memory layout is as follows:

xx xx 0000 xx xx xx xx xx  One  cc CC  

sizeof (A) = 16;0 represents the position of A/b, and 1111 represents the position of C.

 # pragma pack (8   struct   a{ char   A;   double   b;  };  struct   b{ int       I;   struct   A sa;   int   C;  }; 

We look at the layout of structure B, set the specified alignment parameters to 8, in fact, it still does not work, our largest internal type is 8 double, just as the specified alignment parameters are equal. The first member I   must be at the address offset 0. Then the second member is a struct member, we want to find the member's valid alignment parameters, the structure of the effective alignment parameter is the largest of its members of the alignment parameter, for structure A is the B alignment parameter 8, so a's effective alignment is 8. struct member SA to satisfy the alignment requirement, i.e. offset% valid alignment 8 = 0; its address offset should be 8. So the SA and I need to be populated with 4 bytes. Member C is still tightly behind the SA, because the SA occupies 16 bytes, at this time the address offset 24 can meet the C alignment requirements 24 4 = 0, while the total size of structure B also satisfies the alignment rules, the effective alignment of B is the largest of the members, the effective alignment of SA 8. So the total size of B to be divisible by 8, you have to fill the back of C 4 bytes. At this point, the memory layout of structure B is as follows:

xx xx xx xx xx xx xx xx xx xx xx xx xx  One  One  One  one cc cc CC CC  

sizeof (A) = 32;0, respectively, represents the position of i,sa.a,sa.b, and 11111111 represents the position of C.

# pragma pack (8)  struct  a{        char  A;         Double b;  };   struct b{  int  i;   int C;      struct A sa;  };  

Move C to the top of the SA so there is no need to populate any bytes. All members of B just meet the alignment rules. Notice that the B and a in structure A are still filled with bytes, and that they are internally satisfied with their alignment requirements. The memory layout of B at this point is as follows:

xx xx xx xx  One 1111  One xx xx xx xx xx xx xx xx xx  

and sizeof (A) = 24;0, respectively, represents the position of I, sa.a,sa.b, and 11111111 for the position of C.

# pragma pack (4)  struct  a{        char a[9];         Double b;   Char c[];   int d[7];  };  

The effective alignment of array member A is the same as its member type char, 1. The valid alignment of member B is the specified alignment parameter 4, because the specified is smaller than its own. The C array is also 1-byte aligned, the array D is 4-byte aligned, and the specified alignment and its own alignment are all 4. The individual members of the array are tightly arranged, so that 3 bytes are populated between B and a, no bytes are populated between C and B, 3 bytes are populated between D and C, and no bytes are populated after C. sizeof (A) = 80;

C + + memory alignment reprint

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.