When a structural type is defined in C, is its size equal to the sum of the fields (Field) size? How will the compiler places these fields in memory? What is the requirements for ANSI C on the memory layout of the structure? And can our procedure rely on this layout? These issues may be a bit blurred for many friends, then this article tries to explore the secret behind them. First, at least one thing can be affirmed, that is, the ANSI C guarantees that the location of the fields in the structure in memory is increasing with their declaration order, and the first address of the first field is equal to the first address of the entire structure 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 Ok? Fill area? Yes, this is to give the structure field to satisfy the amount of memory to the structure to the structure. So what is the reign of the structure itself? Yes, ANSI C standard specifies that the structure of structural types cannot be more stringent than it requires the most stringent, but this is not forced, VC7.1 is just as strict. Let's take an example (the following environment of all the tests is Intel Celeron 2.4G Win2000 Pro VC7.1, the memory alignment option is "default", ie not specified / zp and / pack option): typedef struct ms1 {char A ; Int b;} MS1; assuming that MS1 is in memory layout as follows (all the memory addresses in all schematic in this article are incremented from left to right): _____________________________ | | ------------------------------------ ------------------ Bytes: 1 4 Because the most stronger alignment requirements in MS1 are B field (int), based on the compiler's alignment rules and ANSI C Standard, the first address of the MS1 object must be a multiple of 4 (INT type alignment mode). So can the B field in the above memory layout meet the INT type alignment requirements? Well, of course I can't. If you are a compiler, how do you clever arrangements to meet the CPU? Oh, after 1 millisecond, you must have drawn the following solution: ______________________________________ | | ///// | b | | /// | | ----- -------------------------------- bytes: 1 3 4 This program is allocated between A and B3 A padding byte so that the B field can also meet the 4-byte alignment of the INT type when the entire Struct object first address meets 4 bytes of alignment requirements. So SizeOf (MS1) is obviously 8, and the offset of the B field relative to the structure of the structure is 4. Very good, right? Now let's exchange the field in MS1: typedef struct ms2 {int A; char b;} ms2; Maybe you think MS2 is simpler than MS1, its layout should be __________________________________ | | | | | | | --------------------- bytes: 4 1 Because the MS2 object is also required to meet 4 bytes alignment, the address and structure of A at this time The first address is equal, so it must also be 4 bytes aligned. Well, it makes sense, but it is not comprehensive. Let us consider what problems with the array that defines a MS2 type. C standard guarantees that the size of any type (including custom structural types) is equal to the size of a separate type of data by the number of array elements. In other words, there is no gap between arrays each element. According to the above scheme, a MS2 array Array layout is: | <- array [1] -> | <- array [2] -> | <- array [3] ..... ________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ A | B | A | B | ............. | | | | | ----------------------- ----------------------------------- BYTES: 4 1 4 1 When the array is 4 bytes When Array [1] .a is also 4 bytes, but Array [2] .a? Array [3] .a ... It can be seen that this scenario does not allow fields of all elements in the array when defining structural arrays to meet the alignment, must be modified as the following form: ___________________________________ | | | | | | /// | --------------------------------- Bytes: 4 1 3 No matter what is defined A separate MS2 variable or an MS2 array that ensures that all fields of all elements are aligned. So, SIZEOF (MS2) is still 8, and the offset of A is 0, and the offset of B is 4. Ok, now you have mastered the basic guidelines of the structure of the structure in vivo, try to analyze a slightly complex point. TypedEf struct ms3 {char A; short b; double c;} ms3; I think you must get the following correct layout: Padding | _____v______________________ | | / | | / | | | | | C | | | | | | | | ------------------------------------- BYTES: 1 2 4 8 SizeOf (SHORT) equal to 2, the B field should start from the even address, so the back of A fills a byte, and sizeof (double) is equal to 8, the c field begins with 8 times the address, the front A , The B field plus the padding byte already has 4 Bytes, so fills 4 bytes later to ensure the alignment of the C field. SizeOf (MS3) is equal to 16, B offset is 2, and the offset is 8. Then look at the fields of the structure or structural types: TypeDef struct MS4 {char A; MS3 B;} MS4; MS3 memory requirements The most stringent field is C, then the alignment of the MS3 type data is consistent with Double (8), the A field should be filled with 7 bytes, so the layout of the MS4 should be: _______________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________ ------------------------------------ BYTES: 1 7 16 Obviously, Sizeof (MS4) is equal to 24 The offset of B is equal to 8. In actual development, we can change the compiler alignment rules by specifying / zp compiling options. For example, specify /zpn (Vc7.1 can be 1, 2, 4, 8, 16) is to tell the compiler's maximum alignment mode number N. In this case, all alignment rules smaller than or equal to the n-byte, the alignment mode of the data type greater than the N-byte is limited to N. In fact, the default alignment option of VC7.1 is equivalent to / zp8. Take a closer look at the description of this option, it will find it solemnly warned the programmer not to use / zp1 and / zp2 options on the MIPS and Alpha platforms, do not specify / zp4 and / zp8 on the 16-bit platform (think why why ?). Changing the compiler alignment option, the controller running result Re-analysis The memory layout of the above four structures will be a good review. Here, we can answer the last question raised in this article. The memory layout of the structure depends on the CPU, operating system, compiler, and compile time alignment option, and your program may need to run on a variety of platforms, your source code may be compiled with different compiler. (Imagine that you provide an open source library for others), so unless it is absolutely necessary, your program will never rely on these weird memory layouts. By the way, if two modules in a program are compiled separately with different alignment options, it is likely to produce some very subtle errors. If your program does have a difficult behavior, you don't prevent carefully check the compilation options for each module. Thinking: Please analyze the memory layout of the following structures on your platform and try to find a reasonable arrangement of the sequence of field declarations to save memory space. 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];}; reference Information: [1] "In-depth understanding of computer system (revised edition)", () Randal E.Bryant; David O'HALLARON, DAVID O'HALLARON, Gong Yuli Yingchun, China Electric Press, 2004 [2] "C: a Reference Manual "(Copy), (and) Samuel P.harbison; Guy L.Stele, People's Posts Publishing House, 2003 Author BLOG: