Deep understanding of C language memory alignment

Source: Internet
Author: User
Tags pack printf relative

  This article mainly introduces the C language memory alignment, a friend in need can refer to the

First explanation of memory alignment   memory alignment can be summed up in one sentence:   The data item can only be stored in a memory location where the address is an integer times the size of the data item   For example, the int type occupies 4 bytes and the address can only be located in 0,4,8.   Example 1:   code as follows: #include <stdio.h> struct xx{        Char b;       &NBSP ; int A;         int C;         Char D; };   int main () {        struct XX bb;         printf ("&a =%p/n", &bb. a);         printf ("&b =%p/n", &bb.b);         printf ("&c =%p/n", &BB.C);         printf ("&d =%p/n", &BB.D);         printf ("sizeof (XX) =%d/n", sizeof (struct xx));           return 0;     The results are as follows: The code is as follows: &a = Ffbff5ec &b = Ffbff5e8 &c = ffbff5f0 &d = ffbff5f4 sizeof (XX) = &nbs P You will find that 3 bytes are vacated between B and a, meaning that after b the 0xffbff5e9,0xffbff5ea,0xffbff5eb is empty, a is stored directly in the 0XFFBFF5EC, because a is 4 and can only be stored in a 4-integer-fold position. The size of the print XX will find that is 16, some peopleMay ask, b after the empty 3 bytes, that should also be 13 ah? What about the other 3? This is a bit more to read in this article, but here's a simple one: the 3 bytes behind D will be wasted, that is to say, the 3 bytes are also occupied by this structure.   can simplify the structure of the structure to reduce the use of memory, for example, the structure can be defined as:   code as follows: struct xx{        Char b;          Char D;         int A;                   int C;                  ;   So the size of this structure is 12, save a lot of space, you can see that in the definition of the structure, we must consider the impact of the memory alignment, so that our program to occupy a smaller memory.   Two. The default alignment factor of the operating system   each operating system has its own default memory alignment factor, and if it is a new version of the operating system, the default alignment factor is typically 8 because the operating system-defined maximum type of storage unit is 8 bytes, such as Long Long (why do this, in the third section), there are no more than 8 bytes of type (for example, int is 4,char is 1,long at 32-bit compile time is 4, 64-bit compile-time is 8). When the default alignment factor of the operating system conflicts with the theory of memory alignment described in the first section, the alignment factor of the operating system is the benchmark.   For example:   Assuming that the operating system's default alignment factor is 4, then a variable of the type long long will not satisfy the first section, that is, a long long structure that can be stored in a position that is divisible by 4 or stored in a position divisible by 8.   You can modify the default alignment factor of the operating system through the #pragma pack () statement, when writing a program, do not recommend modifying the default alignment factor, in the third section explains the reason   Example 2:   code is as follows: #include <stdio.h> #pragma pack (4) struct xx{      &nbsp Char b;         long long A;         int C;         Char D; }; #pragma pack ()   int main () {        struct XX bb;         printf ("&a = %p/n ", &BB.A);         printf ("&b =%p/n", &bb.b);         printf ("&c =%p/n", &BB.C);         printf ("&d =%p/n", &BB.D);         printf ("sizeof (XX) =%d/n", sizeof (struct xx));           return 0;     Printed as follows: Copy code code: &a = ffbff5e4 &b = ffbff5e0 &c = Ffbff5ec &d = ffbff5f0 sizeof (XX) = 20   found 8 bytes of a, stored in a location that cannot be divisible by 8, stored in a position divisible by 4, taking the default alignment factor of the operating system.   three. The reason for the memory alignment   memory alignment is a strategy taken by the operating system to quickly access memory, simply to place two accesses to a variable. When the operating system accesses memory, it reads a certain length each time (this is the operating system's default alignment factor, or an integer multiple of the default alignment factor). If there is no memory alignment, the two accesses to the bus are generated in order to read a variable.   For example, assuming there is no memory alignment, the variable position of the structure XX will appear as follows:       Code is as follows: struct xx{        Char b;        //0xffbff5e8         int A;            //0XFFBFF5E9                int C;            //0xffbff5ed               Char D;        //0XFFBFF5F1};   The operating system reads the 0XFFBFF5E8-0XFFBFF5EF memory first, then reads the 0XFFBFF5F0-0XFFBFF5F8 memory, in order to obtain the value C, needs to merge two sets of memory, to consolidate, thus severely reduces the memory access efficiency. (This involves the cliché question, space and efficiency which is more important?) There is no discussion here).   So you can understand why the first variable of the struct, regardless of type, is divisible by 8 (since access memory starts with an integer multiple of 8, in order to increase the efficiency of reading)! The problem of   memory alignment mainly exists in the understanding of the distribution of struct and other composite structures in memory.   First understand the concept of memory alignment. Many actual computer systems have a limit on the location of the underlying type data in memory, and they require that the value of the first address of the data be a multiple of a number k (usually 4 or 8), which is the so-called memory alignment.   This k under different CPU platform, different compiler performance is also different. such as 32-bit word length of the computer and 16-bit word length of the computer. This is a little far from us. Our development involves two major platforms, Windows and Linux (Unix), and the compilers involved are mainly Microsoft compilers (such as CL), and GCC. The purpose of   memory alignment is to make the first address of each basic data type a multiple of the corresponding K, which is the ultimate weapon to understand the memory alignment. You also need to distinguish between the compiler's differences. Understand that these two points can basically handle all the problems of the alignment of the memory.   K:1 in different compilers, for Microsoft compilers, for eachThe size of the base type is this K. In general, the char type is 8,int to 32,long for 32,double 64. 2, for the GCC compiler under Linux, the specified size is less than or equal to 2, the K value is its size, greater than or equal to 4 of 4.   Understand that the above description of the struct and other composite structure of the memory distribution should be very clear.   Let's look at one of the simplest types: struct members are basic data types, such as:     code as follows: struct Test1 {char A; short b; int c; long D; double e;} ;   on the Windows platform, under Microsoft compilers:   Suppose starting with 0 addresses, first A's K value is 1, its first address can make any position, so a occupies the first byte, namely address 0; then B's K is 2, and his first address must be a multiple of 2, not 1. , so address 1 that byte is populated, b the first address is address 2, Occupy address 2, 3, then to C,c K value of 4, his first address is a multiple of 4, so the first address is 4, occupy address 4,5,6,7, and then to D,d K value is 4, so his first address is 8, occupy address 8,9,10, 11. Finally to E, his K value is 8, the first address is a multiple of 8, so the address 12,13,14,15 is populated, his first address should be 16, occupy address 16-23. Obviously its size is 24.   This is the distribution of test1 in memory. We create a test1 type of variable, a, B, C, D, E, respectively, assigned 2, 4, 8, 16, 32. Then print out each byte in memory in order from the low address the corresponding 16 number is: 2 0 4 0 8 0 0 0 Ten 0 0 0 0 0 0 0 0 0 0 0 0 0   Verification: Obviously the inference is correct.   on Linux platform, GCC compiler: Assuming starting from 0 addresses, first A's K value is 1, its first address can make any position, so a occupies the first byte, namely address 0; then B's K value is 2, and his first address must be a multiple of 2, not 1, so address 1 that byte is populated, b The first address is address 2, Occupy address 2, 3, then to C,c K value of 4, his first address is a multiple of 4, so the first address is 4, occupy address 4,5,6,7, and then to D,d K value is 4, so his first address is 8, occupy address 8,9,10,11. Finally to E, starting here is different from the Microsoft compiler, his K value is not 8, is still 4, so its first address is 12, occupy address 12-19。 Obviously its size is 20.   Validation: We set up a test1 type of variable, a, B, C, D, E assigned values 2, 4, 8, 16, 32 respectively. Then print out each byte in memory in order from the low address the corresponding 16 number is: 2 0 4 0 8 0 0 0 Ten 0 0 0 0 0 0 0 0 0   Obviously the inference is also correct.   Next, take a look at a few special cases, to avoid trouble, no longer describe the memory distribution, only calculate the size of the structure.   First: Nested structure     code as follows: struct test2 {char f; struct test1 g;};   Under the Windows platform, Microsoft compilers:   In this case, if the second member of the Test2 is taken apart to study the memory distribution, then you know that Test2 's member F occupies address 0, G.A occupy address 1, the future of the memory distribution is unchanged, still meet all the basic data members of the first address is its corresponding k multiples of this principle, then the size of the test2 is still 24. But in fact the size of the test2 is 32, because: the structure of the test2 can not change the memory distribution of the test1, so in order to make the test1 of each member still meet the requirements of alignment, F members need to fill a certain number of bytes, it is not difficult to find that the number should be 7, In order to ensure test1 alignment. So the test2 is incremented by 8 bytes relative to Test1, so the test2 size is 32.   Under the Linux platform, GCC compiler:   Similarly, if the second member of the Test2 is taken apart to study the memory distribution, then you know that Test2 's member F occupies address 0, G.A occupy address 1, the future of the memory distribution is unchanged, still meet all the basic data members of the first address is its corresponding k multiples of this principle, then the size of the test2 is still 20. But actually the size of the test2 is 24, this is also because: the structure of the test2 can not change the test1 memory distribution, so in order to make the test1 of the various members still meet the requirements of alignment, F members need to fill a certain number of bytes, it is not difficult to find that the number should be 3, In order to ensure test1 alignment. So the test2 is incremented by 4 bytes relative to Test1, so the test2 size is 24.   Second: bit-segment alignment     code as follows: struct TEST3 {unsigned int a:4; unsigned int b:4; CHAR c; };   or code as follows: struct TEST3 {unsigned int a:4; int b:4; char c;};   on the Windows platform, under Microsoft compilers:   Several adjacent numbers of the same type (signed and unsigned, as long as the base type is the same number), they can be viewed as a whole if they occupy no more than the base type size. Different types of numbers should follow their own alignment. For example: Test3, A, B can be as a whole, they as an int data to treat, so the size of Test3 is 8 bytes. And the values of A and B are sorted in memory from low levels, with the top 0-3 and 4-7 bits in the 4-byte range   If the TEST4 bit format     code is as follows: struct TEST4 {unsigned int a:30; Unsigne d int B:4; char c; };   The size of the Test4 is 12 bytes, and the value A and B are distributed between the first 30 bits of 4 bytes, and the first 4 bits of the second 4 byte respectively.   such as TEST5 is the following form     code as follows: struct TEST5 {unsigned int a:4; unsigned char b:4; char c;};   So because of the different types of int and char, they are aligned in their own way, so the size of the test5 should be 8 bytes, and the values of A and B are in the first 4 bits and the top 4 bits of the 5th byte in each 4 byte.   on Linux platform, GCC compiler:     code as follows: struct TEST3 {unsigned int a:4; unsigned int b:4; char c;};   GCC, adjacent members, regardless of the type is the same, the number of digits and more than the size of the first of these members, in the structure with a K value of 1 aligned, outside the structure K value of its basic type value. In the case of no more than the in-memory sequence. such as Test3, whose size is 4. The a,b values in memory are ranked 0-3 and 4-7 bits in the first four bytes, respectively.   If the TEST4 bit has the following format   code as follows: struct TEST4 {unsigned int a:20; unsigned char b:4; char c;}; &nbsp The size of the Test4 is 4 bytes, and the values of A and B are distributed in the first 4-byte 0-19-bit, and 20-23-bit, and c is stored in the 4th byte. If the TEST5 is the following form the code is as follows: struct TEST5 {unsigned int a:10; unsigned char b:4; short C;};   The size of the test5 should be 4 bytes and the A,b value is 0-9-bit and 10-13-bit. c is stored in the latter two bytes. If the size of a becomes 20 then the size of the test5 should be 8 bytes. The   code is as follows: struct TEST6 {unsigned int a:20; unsigned char b:4; short C;};   At this point, Test6 's A, b altogether occupies 0,1,2 a total of 3 bytes, C's K value is 2, can actually 4 position, but outside the structure, a to int the way to align. That is, two consecutive Test6 objects stored in memory, the first place of a is guaranteed to be a multiple of 4, then C must be more than 2 digits after. So the size of the Test6 is 8 bytes. The part of   about the segment structure is more complex. I've known so much for a while.    

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.