Memory alignment and Memory layout "Go" for struct-type data in ANSI C

Source: Internet
Author: User
Tags microsoft c

Transferred from: http://blog.chinaunix.net/uid-25909619-id-3032209.html

When a struct type is defined in C, is its size equal to the sum of the fields (field) sizes? How will the compiler place these fields in memory? What are ANSI C requirements for the structure's memory layout? And can our program rely on this kind of layout? These questions may be a little vague for many friends, so this article tries to explore the secrets behind them.

first, at least one thing is certain, that is, ANSI C guarantees that the location of the fields in the structure in memory is in accordance with their declaration order. is incremented, and the first address of a field is equal to the first address of the entire struct instance. For example, there is such a structure:

struct vector{int x, y, z;} s;
int *p,*q,*r;
struct vector *ps;

p = &s.x;
Q = &s.y;
r = &s.z;
PS = &s;

ASSERT (P < q);
ASSERT (P < R);
ASSERT (Q < R);
ASSERT ((int*) PS = = p);
//The assertion above must not fail

At this point, a friend might ask, "Does the standard stipulate that adjacent fields are adjacent in memory?". Well, sorry, ANSI C does not guarantee that your program should not rely on this hypothesis at any time. Does this mean that we will never be able to sketch out a clearer and more precise structure in vivo ? Oh, of course not. But let's take a moment out of this problem and focus on another important issue ———— memory alignment.

many real computer systems restrict the location of basic types of data in memory, and they require that the value of the first address of the data be aA multiple of the number K (usually 4 or 8), which is called memory alignment, and this k is called the number of pairs of Zimo for that data type (alignmentmodulus). When the ratio of one type S pair of Zimo number to the Zimo number of another type T is an integer greater than 1, we call the alignment requirement of type Sstronger than T (strict), and T is weaker than s (loose). This mandatory requirement simplifies the design of the transfer system between the processor and the memory, and improvesthe speed at which the data is read. For example, such a processor, every time it reads and writes memory from a certain 8 times times the address of the beginning, read out or write 8bytes of data, if the software can guarantee that the double type of data from 8 times times the address of the beginning, then read or write a double type of data will only need toone-time memory operation. Otherwise, we might need two memory operations to complete this action, because the data may be exactly across two alignedrequires 8 bytes of memory on the block. Some processors may fail if the data does not meet the alignment requirements, but Intel's IA32 architecture's processorit works correctly regardless of whether the data is aligned. But Intel advises that if you want to improve performance, then all the program data should be asaligned. The Microsoft C compiler (Cl.exe for 80x86) under the Win32 platform uses the following alignment rules by default: Any basic data type Tthe number of Zimo is the size of T, which is sizeof (t). For example, a double type (8 bytes) requires that the address of that type of data be always a multiple of 8, and the Char type data (1 bytes) can start at any one address. GCC under Linux pursues a different set of rules (found in the data andnot verified, as in the case of an error): Any 2-byte size (including single-byte?) The Zimo number of data types (such as short) is 2, while all other hyper -data types that are over 2 bytes (such as long,double) have 4 pairs of Zimo.

now come back to the struct we care about. ANSI c specifies that the size of a struct type is the sum of the size of all its fields and the size of the fill area between fields or the end of a field. Well? Fill area? Yes, this is the extra space allocated to the struct for the structure field to satisfy the memory alignment requirements . So what are the alignment requirements of the structure itself? Yes, the ANSI C standard stipulates that the alignment requirements of a struct type cannot be more restrictive than the one that is most stringent in all of its fields (but this non-mandatory requirement, VC7.1 is just as strict as that). Let's take a look at an example (the following test environment is the Intel Celeron 2.4G + WIN2000 PRO + vc7.1, the Memory-aligned compilation option is "Default", that is, the/zp and /pack options are not specified):

typedef struct MS1
{
Char A;
int b;
} MS1;

       ______________________ _______
       |       |                    |
       |   a   |        b           |
       |       |                    |
       +---------------------------+
 Bytes:    1              4

can. If you were a compiler, how would you skillfully arrange it to satisfy the CPU's quirks? Oh, after 1 milliseconds of hard thinking, you must have come to the following

This scheme allocates more than 3 padding (padding) bytes between A and B, so that the first address of the entire struct object satisfies the 4-byte alignment requirement , the B field must also meet the 4-byte alignment rules for Int. Then sizeof (MS1) should obviously be 8, and the B field offset from the first site of the struct is 4. Very well understood, right? Now let's swap the fields in MS1 for the order:

typedef struct MS2
{
int A;
Char b;
} MS2;

Perhaps you think MS2 is simpler than MS1 's, and its layout should be

because the MS2 object also satisfies the 4-byte alignment rule, the address of a is equal to the first address of the struct, so it must also be 4-byte aligned . Well, the analysis makes sense, but it's not comprehensive. Let's consider what the problem is with defining an array of type MS2. The C standard guarantees that the size of an array of any type (including a custom struct type) must be equal to the size of a separate data of that type multiplied by the number of elements of the array . In other words, there is no space between the elements of the array. In the above scenario, the layout of an array of MS2 arrays is:

|<-array[1]->|<-array[2]->|<-array[3] .....

__________________________________________________________
|       |              |      | |
|   A |      B |   A | B | .......
|       |              |      | |
+----------------------------------------------------------
Bytes:4 1 4 1

when the first address of an array is 4-byte aligned, ARRAY[1].A is also 4-byte aligned, but what about ARRAY[2].A? Array[3].a .... It? It is possible to see that this scheme does not allow the fields of all elements in the array to satisfy the alignment rules when defining an array of structs, and must be modified to the following form:

now whether you define a separate MS2 variable or an MS2 array, all the fields of all elements are guaranteed to meet the alignment rules. Then sizeof (MS2) is still 8, and A's offset to 0,b is 4.

OK, now that you have mastered the basic principles of the structure's in-vivo layout, try to analyze a slightly more complex type.

typedef struct MS3
{
Char A;
Short B;
Double C;
} MS3;

I think you will be able to draw the following correct layout diagram:

        padding  
            |
      _____v_________________________________
      |    |/|     |/////////|                |
      | A |/|  b  |/padding/|       c        |
      |   |/|     |/////////|                |
      +-------------------------------------+
bytes:  1  1   2        4            8

sizeof (short) equals the 2,b field should start with an even address, so a byte is populated after a, and sizeof (double) equals 8,cfield to start from 8 times times the address, the front of a, B fields plus the padding byte already has 4 bytes, so b after the padding 4 bytes can be guaranteed CThe alignment of the field is required. sizeof (MS3) equals the offset of 16,b is 2,c offset is 8. Then look at the structure of the field or structure type of the situationConditions:

typedef struct MS4
{
Char A;
MS3 b;
} MS4;

MS3 The most stringent memory requirements in the field is C, then MS3 type data for the Zimo number is the same as double (8), the A field should be populated after 7 bytes, so the layout of MS4 should be:
        |       |///////////|                  |
       |   a   |//padding//|        b         |
       |       |///////////|                  |
       +-------------------------------------+
 Bytes:     1         7             

Obviously, sizeof (MS4) equals the offset of 24,b equals 8.

in real-world development, we can change the compiler's alignment rules by specifying the/ZP compilation option. For example, specifying/ZPN (n in VC7.1 can be 1, 2, 4, 8, 16) is telling the compiler that the maximum number of Zimo is n. In this case, all of the base data types that are less than or equal to n bytes are Zishi the same as the default, but the number of Zimo for data types greater than n bytes is limited to n. In fact, VC7.1 's default pair of alignment is equivalent to /ZP8. Take a closer look at MSDN's description of this option and you'll find it solemnly warns programmers not to use the/ZP1 and/ZP2 options on MIPS and Alpha platforms , or to specify/ZP4 and/ZP8 on 16-bit platforms (think about why?). )。 Changing the alignment options of the compiler and re-analyzing the memory layout of the above 4 structures will be a good review against the program's running results.

Here we can answer the last question raised in this article. The memory layout of a struct relies on the alignment options of the CPU, operating system, compilers, and translations, and your program may need to run on multiple platforms, and your source code may be compiled by different people with different compilers (try to provide someone with an open source library), So unless absolutely necessary, your program will never rely on these weird memory layouts. Let's say that if two modules in a program are compiled with different alignment options, it is likely to produce some very subtle errors . If your program does have a hard-to-understand behavior, check the compilation options for each module carefully.

Study Questions: Please analyze the memory layout of the following structures on your platform and try to find a way to properly arrange the order of the field declarations to do The amount of memory space saved.

A. struct P1 {int A; char b; int c; char D;};
B. struct P2 {int A; char b; char c; int D;};
C. struct P3 {short a[3]; char b[3];};
D. struct P4 {short a[3]; char *b[3];};
E. struct P5 {struct P2 *a; char b; struct P1 a[2]; };

Resources:

"1" in-depth understanding of computer Systems (revised edition),
With Randal e.bryant; David O ' Hallaron,
Gong Yili Rei Chun,
China Power Press, 2004

"2" "C:a Reference Manual" (photocopy version),
With Samuel P.harbison; Guy L.steele,
People's post and Telecommunications press, 2003

Memory alignment and Memory layout "Go" for struct-type data in ANSI C

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.