Keywords: sizeof, byte alignment, multi-inheritance, virtual inheritance, member function pointer
Beforeward:? Sizeof, a guy who is unstoppable, caught countless rookie, the shrimp, I didn't have a relaxation, and I made a great thoughts of "hard me, a happy thousands of people", I decided to put it as much as possible Detailed summary. But when I summed it, I found that this problem can be both simple and complicated, so this article is not suitable for beginners, and even there is no need to master a masterpiece. But if you want to "know it, better", then this article can help you. The rookie I have not been in-depth for C , including mistakes, welcome to throw the bricks.
1. Definition:? What is the sacred? SizeOf is an operator in C / C is also, simply saying that the role is to return an object or type of memory byte number of memory bytes. ? The interpretation of MSDN is:? The sizeof keyword gives the Amount of Storage, IN BYTES, Associated with a variable or a type (include ". ?? This key size_t.? Its return value is Size_T, defined in the header file stddef.h. This is a value dependent on the compilation system. Typedef unsigned int size_t ;? the world compiler Lin Lin's total, but as a norm, they will guarantee the sizeof value of char, soudned char and unsigned char, after all, char is us The smallest data type for programming can be programmed.
2. Syntax:? SizeOf has three grammar forms, as follows:? 1) sizeof (object); ?? // sizeof (object);? 2) sizeof (type_name);? // sizeof (type) ;? 3) Sizeof Object; ?? // sizeof object; ??? So,? INT i;? sizeof (i);? // ok? sizeof (int);? // ok? sizeof int; ? // error? Since writing method 3 can be used to write approach, in order to unify the form and reduce the burden of our brain, the third way of writing, forget it! In fact, the size of the SIZEOF calculation object is also converted to the type of object type, that is, the different objects of the same type are consistent. Here, the object can further extend to the expression, ie, SizeOf can be evaluated to an expression, the compiler determines the size according to the final result type of the expression, generally does not calculate the expression. Such as:? SizeOf (2);? // 2 is int, so equivalent to sizeof (int) ;? SizeOf (2 3.14); // 3.14 type is Double, 2 will also be upgraded into Double type , So equivalent to SizeOf (Double); SizeOf can also call a function call, the result is the size of the function returns the type, the function will not be called, let's take a complete example:? Char foo () ? {?? printf ("foo () HAS been Called./n" ";??return 'a';?}? int main ()? {?? size_t sz = sizeof (foo ()); // foo The return value type is char, so SZ = sizeof (char), foo () will not be called ?? Printf ("SizeOf (foo ()) =% D / N", SZ);?}? C99 Standards, functions, unable to determine the type of expression, and bit-field members cannot be calculated by the sizeof value, that is, the following writes are wrong:? SizeOf (foo); ?? // error? Void foo2 ) {}? sizeof (foo2 ()); // error
• STRUCT S? {?? unsigned int F1: 1; ?? unsigned int F2: 5; ?? unsigned int F3: 12;?}; sizeof (s.f1); ?? // error?
3. Sterity of SIZEOF? SizeOf's calculation occurs at the compilation time, so it can be used as a constant expression, such as:? CHAR ARY [SIZEOF (INT) * 10] ;? // OK? The latest C99 standard regulations SIZEOF can also be calculated at runtime, as shown below in DEV-C :? int N;? n = 10; // n Dynamic assignment? CHAR ARY [N]; // c99 also supports arrays Dynamic definition? Printf ("% d / n", sizeof (ary)); // ok. Output 10? But in the compiler without complete implementation of the C99 standard, the above code is not compiled in VC6. . So we'd better think SIZEOF is executed in the compile period, which will not cause errors to make the program's portability.
4. SIZEOF? SIZEOF? The basic data type here refers to the simple built-in data type of short, int, long, float, double, because they are all associated with the system, so the value may be different under different systems. This must cause our attention, try not to make trouble to the transplantation of our program in this regard. In general, in the 32-bit compilation environment, the value of sizeof (int) is 4.5. The sizeofer of the pointer variable can learn the data structure, you should know that the pointer is a very important concept, it records another object the address of. Since it is to store the address, it is of course equal to the width of the internal address bus of the computer. So in the 32-bit computer, the return value of a pointer variable must be 4 (note that the result is in bytes), which can be expected that the sizeOf result of the pointer variable in the future 64-bit system is 8. ? char * pc = "abc";? int * pi;? string * ps;? char ** PPC = & PC;? VOID (* pf) ();? // function pointer? SizeOf (PC);? // The result is 4? Sizeof (pi); / / The result is 4? Sizeof (PS);? / / The result is 4? Sizeof (PPC);? // The result is 4? Sizeof (PF);? // result 4? The sizeof value of the pointer variable does not have any relationship with the object referred to by the pointer, which is because all the pointer variables are equal to the memory size, so the MFC message processing function uses two parameters WPARAM, LPARAM can deliver a variety of complex messages. Structure (pointer to the structure).
6. The sizeof value of the array SIZEOF® array is equal to the number of memory bytes occupied by the array, such as? CHAR A1 [] = "abc"; int A2 [3] ;? sizeof (A1); / / result is 4 There is a null terminator in the end of the string still there is a null terminator? SizeOf (A2); / / The result is 3 * 4 = 12 (depending on int)? Some friends have just started SIZEOF as a number of group elements, now, now, You should know this is not right, then how should you ask the number of array elements? Easy, usually there are two ways:? Int C1 = sizeof (a1) / sizeof (char); // Total length / single element length? INT C2 = SizeOf (A1) / Sizeof (A1 [0]); / / Total length / The length of the first element? Write here, mention the question, what should the C3 in the following? ? Void foo3 (Char A3 [3])? {?? int C3 = sizeof (A3); // C3 == ??}? Void foo4 (char A4 [])? {?? int C4 = Sizeof (A4) ; // c4 == ??} ?? Maybe when you try to answer the value of C4, C3 has been recognized, yes, C3! = 3. Here the function parameter A3 is no longer an array type, but it turns into a pointer, which is equivalent to char * a3, why? If you think about it, it is not difficult to understand. When we call the function foo1, will the program allocated an array of 3 in the stack? will not! The array is "in-service", the caller only needs to pass the address of the arguments, so A3 is naturally a pointer type (char *), and the value of C3 is 4.
7. Structural SIZEOF? This is a problem that beginners asking for the most, so there is a need for more written inks. Let's take a structure first:? Struct S1? {?? char C; ?? Int i ;?}; ?? QIZEOF (S1) is equal? Smart, you start thinking, Char accounts for 1 byte, Int accounts for 4 bytes, then add up should be 5. Is that right? Have you tried it on your machine? Maybe you are right, but it is very likely that you are wrong! The result of the default setting is 8 in VC6. ? Why? Why am I always the one who's hurt? ? Please don't be frustrated, let's take a look at the SizeOf's result is equal to the number of internal memory by the object or type, ok, let us see the memory allocation of S1:? S1 S1 = {'a', 0xfffffffff}; after defining the above variables, add breakpoints, run the program, observe the memory of S1, what did you find? Taking my VC6.0 as an example, S1's address is 0x0012FF78, its data content is as follows: ?? 0012ff78 :? 61 CC CC CC FF FF FF? What did you find? How to mix 3 bytes of CC in the middle? Take a look at the description of MSDN:? When Applied to A Structure Type or Variable, SizeOf Returns The Actual Size, Which May Include Padding Bytes Inserted for Alignment.? This is the legendary byte alignment! An important topic appeared. Why do you need a byte alignment? The principle of computer composition teaches us to help speed up the computer's number of speeds, otherwise it will have a multi-flowering command cycle. To this end, the compiler will process the structure by default (this is also the data variable in other parts, so that the basic data type (Short, SHORT, etc.) capable of being able to be completely removed, so that the width is 4 The basic data type (INT, etc.) are located on an address that can be 4 completely, and push it. Thus, the middle of the two numbers may need to add a padding byte, so the sizeof value of the entire structure increases. Let us exchange the location of CHAR and int:? Struct s2? {?? int i; ?? char c ;?}; look at the result of SIZEOF (S2), how is it still 8? Take a look at memory, there is still three filling bytes behind the member c, which is why? Don't worry, summarize the law. The detail of the byte alignment and the compiler implementation, but in general, three guidelines:? 1) The first address of the structural variable can be removed by the size of its widest basic type member;? 2) Structural body The offset of members relative to the structure of the structure is an integer multiple of the membership size, if necessary, the compiler will add fill bytes between members (INTERNAL ADDING) ;? 3) Structural body The size is an integer multiple of the large-scale basic type member size of the structure. If a compiler is needed to add a fill byte after the last member. For the above criteria, there are a few need to explain:? 1) The front is not the address of the structural member is an integer of its size, how can I say the offset? Because there is a 1st point, we can only consider the offset of members, so thinking about it. Think about why.
• The offset of a member of the structure relative to the structure of the structure can be obtained by macro OFFSTOF (), this macro is also defined in stddef.h, as follows:? # Define offsetof (s, m) ?? (size_t) ?? (SIZE_T ) & (((S *) 0) -> M)? For example, if you want to get the offset of C in S2, how is it? size_t pos = offsetof (S2, c);? // POS is equal to 4? 2) The basic type refers to the built-in data type such as Char, Short, Int, Float, Double mentioned above, which refers to the size of its sizeOf. Since members of the structure can be a composite type, such as another structure, it should include sub-members of the composite type member when looking for the widest basic type member, rather than regarding composite members as a whole. However, when determining the offset position of the composite type member, the composite type is treated as an overall. It is a bit 拗拗 here, thinking is a little scratch, or let us look at the example (the specific value is still vc6 as an example, will no longer explain): ?? Struct S3? {?? char C1; ?? s1 s ; ??????????????? The wide simple and simple member of S1 is int, S3 is considering the broadcase type member, so the broadest and simple type of S3 is int, so Through the variable defined by S3, its storage space first address needs to be 4, and the value of the entire SIZEOF (S3) should also be 4. ? The offset of C1 is 0 and s offset? At this time, S is a whole, which also satisfies the three criters in front of the structural variable, so it is 8, the offset is 4, and the C1 and S need three filling bytes, and C2 and S are It is not required, so the offset of C2 is 12, and the size of C2 is 13, 13 is not 4, which is still added to three filling bytes at the end. Finally, the value of SIZEOF (S3) is 16. • Through the above description, we can get a formula: • The size of the structure is equal to the last member's offset plus the size of the size plus the number of padded bytes, namely:? Sizeof (struct) = Offsetof Item) SizeOf (trailing padding) ??? He here, friends should have a new understanding of SizeOf, but don't be too early, there is an important parameters affecting Sizeof Not mentioned, then the compiler's Pack instruction. It is used to adjust the structure alignment, and different compiler names and use methods are slightly different. VC6 can be implemented by #pragma pack, or the / zp compilation switch can also be modified.
#Pragma Pack's basic usage is: #pragma pack (n), n is the number of bytes, with a value of 1, 2, 4, 8, 16, the default is 8, if this value is a SIZEOF value of the structure Small, then the offset of the member should be subject to this value, ie, the offset of structural members should take the minimum value of the two, the formula is as follows:? Offsetof (item) = min (n, sizeof Item))? Look at the example:? # pragma pack (push)? // Set the current Pack Set the stack save? #pragma pack (2)? // must be used before the structural definition? Struct S1? {?? char c; ?? INT i;?}; ?? struct s3? {?? char C1; ?? s1 s; ?? CHAR C2?};? # Pragma Pack (POP) // Restore previous pack settings? Calculate SIZEOF When S1), the value of MIN (2, SIZEOF (I)) is 2, so the offset of I is 2, and the sizeOf (I) is equal to 6, which can be divided by 2, so the size of the entire S1 is 6. Similarly, for the offset of SizeOf (S3), S is 2, the offset of C2 is 8, plus SIZEOF (C2) equal to 9, cannot be divided by 2, add a padding byte, SIZEOF (S3) Equal to 10. Now, friends can easily take a breath, :)? At any point, "empty structural" (excluding data members) is not 0, but 1. Imagine a variable of "not occupying the space" to take the address, how is the two different "empty structural" variables distinguished? As a result, the "empty structure" variable has to be stored so that the compiler can only be occupied by the space allocated one byte. As follows:? Struct S5 {} ;? sizeof (S5); / / The result is 1?
8. SIZEOF? SIZEOF? As mentioned earlier, the bitmaster may not be individually taken, and we will discuss the SizeOf of the structure containing the domain, just considering its specialty and specializes Column. ? C99 specifies int, unsigned int and bool as a bit domain type, but the compiler has extends almost, allowing other types of types. • The main purpose of the use bit is to compress storage. Its approximate rules:? 1) If the type of neighbor domain field is the same, its bitwnewidth is less than the type of SIZEOF size, then the following fields will follow the previous field. Store until it is not allowed to receive;? 2) If the type of neighbor domain field is the same, its bit width and greater than the type of SizeOf size, then the following field will start from the new memory cell, its offset is its type The size of the size;? 3) If the type of the neighboring bit field field is different, the specific implementation of each compiler is different, and the VC6 takes no compression mode, DEV-C takes a compression method;? 4) If the bit field field Inserting a non-bit field field is not compressed; 5) The total size of the entire structure is an integer multiple of the widest basic type member size. ?? Let's take a look at the example. ? Sample 1:? Struct bf1? {?? char f1: 3; ?? Char F2: 4; ?? CHAR F3: 5 ;?};? 内 内 布 布::? | _F1__ | __f2__ | _ | ____f3 ___ | ____ |? | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ | _ |? 0 ?????? 3 ??????? ?? 7 8 ??????????? 13 ?????? 16? The bit domain type is char, the first byte can only accommodate F1 and F2, so F2 is compressed to the first In the byte, F3 can only start from the next byte. Therefore, the result of SIZEOF (BF1) is 2. ? Sample 2:? Struct bf2? {?? char f1: 3; ?? Short F2: 4; ?? CHAR F3: 5 ;?}; Due to the difference between the adjacent bit domain type, SizeOf in VC6 is 6, 2 in DEV-C is 2. ? Sample 3:? Struct bf3? {?? char f1: 3; ?? char f2; ?? CHAR F3: 5 ;?};? Non-position field is inserted therein, no compression, in VC6 and DEV- The size obtained in C is 3.9. The SizeOf? Structural body of the consort is sequentially in memory organization, and the consortium is overlapping, and each member shares a memory, so the SizeOf of the entire consort is every Maximum value of members SIZEOF. Members of the structure can also be a composite type, here, composite type members are considered as a whole. Therefore, in the following example, the sizeOF value of the U is equal to SIZEOF (S). ? UNION u? {?? int i; ?? char c; ?? s1 s ;?};
?