Sizeof, ultimate (1)
Keywords: sizeof, byte alignment, bit field, multi-inheritance, virtual inheritance, member function pointer
Forward statement: SizeOf, a guy who is unstoppable, caught countless rookie, the shrimp, I didn't have a relaxation, and I made a great idea of "hard me, a happy thousands of people", I decided to put it as much as possible Summary. But when I summed it, I found that this problem can be easier and complicated, so there is not suitable for beginners, and even there is no need to master. But if you want to "know it, better", then this article can help you. The rookie has not been in-depth for C , including mistakes, welcome to throw the bricks.
1. Definition: Where is SIZEOF? 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. Explanation on MSDN is: The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types) This keyword returns a value of type size_t its return type size_t, in the header file. Stddef.h is defined. This is a value dependent on the compilation system. It is generally defined as TypedEf unsigned int size_t; the world compiler Lin Lin is always in total, but as a norm, they will guarantee the sizeof value of char, souded char and unsigned char, after all, char is our programming The minimum data type for use.
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 i; // ok sizeof (int); // Ok sizeof int; // error Since the writing 3 can be used to write method 1, in order to unify and reduce our brain The burden, the third type 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 same type of different objects have a SIZEOF value. 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 of Double, 2 will also be upgraded into Double type, so wait Price from sizeof (doubleof) 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 () return value type is char, so SZ = SIZEOF (charr ), Foo () does not call Printf ("SizeOf (Foo ()) =% D / N", SZ);} C99 standard specified, function, unable to determine the type of expression and bit domain (Bit-Field) Members cannot be calculated by the SIZEOF value, that is, the following writes are wrong: sizeof (foo); // Errorvoid foo2 () {} sizeof (foo2 ()); // error
Struct s {unsigned Int f1: 1; unsigned int F2: 5; Unsigned Int F3: 12;}; sizeof (s.f1); // error
3. The calculation of SIZEOF's constant SIZEOF occurs at the compilation time, so it can be used as a constant expression, such as: char Ary [sizeof (int) * 10]; // OK latest C99 standard specified SizeOf can also be The runtime is calculated, as shown below can be performed correctly in DEV-C : int N; n = 10; // n Dynamic assignment char Ary [n]; // c99 also supports the dynamic definition of arrays PRINTF ("% D) / n ", sizeof (ary); // ok. Output 10 but does not pass in a compiler that does not fully implement 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 here's basic data type refers to Simple built-in data types such as short, int, long, float, double, because they are all associated with the system, so at different systems may be different, this Be sure to attract us, try not to make trouble to your own programs in this regard. In general, in the 32-bit compilation environment, the value of sizeof (int) is 4.5. You should know the pointer is a very important concept, which records the address of another object. . 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); / / result is 4 SizeOf (Pi); / / The result is 4 sizeOf (PS); / / The result is 4 sizeOf (PPC); / / The result is 4 sizeOf (PF); / / The result is that the SizeOF value of the 4 pointer variable is not any relationship with the object refers to the pointer. It is precisely 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 message structures (using pointers 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, the string end of the string There is also a NULL terminator SIZEOF (A2); / / The result is 3 * 4 = 12 (depending on the int) some friends who have just started the number of group elements, now you should know this is not So 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 The length of the first element is written here, will mention one, the following C3, the C4 value should be? 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, you have realized that C3 has an error, 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 with the most questions, so there is a need for a lot of pen ink. Let us first look at a structure: struct s1 {char c; int i;}; ask SIZEOF (S1)? 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 wonder the SizeOf's definition - the result of SizeOf is equal to the number of memory byyrans, ok, ok, let's see the memory allocation of S1: S1 S1 = {' A ', 0xfffffffff}; After defining the above variables, add breakpoints, run the program, observe the memory where S1 is located, what did you find? Taking my VC6.0 as an example, the address of S1 is 0x0012FF78. The data is as follows: 0012ff78: 61 CC CC CC FF FF FF found? 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! 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 position of CHAR and INT in S1: 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 byte alignment and compiler implementation, but in general, the three guidelines are met: 1) The first address of the structural variable can be removed by the size of its widest basic type member; 2) Each member of the structure is relatively The offset of the structural header address is an integer multiple of the member size. If a compiler is needed, the compiler will add a fill byte (INTERNAL ADDING); 3) The total size of the structure is structured. The widest and basic type member size is integrated, if a compiler is required to add a fill byte after the last member. For the top guidelines, there are a few things to explain: 1) The front is not the address of the structure of the structure is the integer of its size, how can it say that the offset is? 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 a member relative to the structure of the structure can be obtained by macro OFFSTOF (), which 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, the method is size_t pOS = Offsetof (S2, C); // POS is equal to 4 2) The basic type means the previous mentioned A built-in data type like char, short, int, float, double, "Data Width" herein 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 about a little scratching, 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; char C2}; S1 The type of broad basic member is int, S3 is to see S1 "dispersion" when considering the widest basic type member, so the widest basic type of S3 is int, so that the storage space first address defined by S3 It is necessary to be 4, the value of the entire SIZEOF (S3) should also be divided by 4. Is the offset of C1 of 0 and S? 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 offset of the last member plus the size of the size plus the number of padded bytes, namely: sizeof (struct) = offsetof (Last Item) Sizeof (trailing padding) here, friends should have a new understanding of SizeOf, but don't be too early, there is an important parameter that affects SizeOf has not been mentioned, then It is the Pack Directive of the Compiler. 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 )) Re-see example: #pragma pack (push) // Set the current Pack Set the stack to save #pragma pack (2) // must use Struct S1 {char C; INT I;}; Struct S3 { CHAR C1; S1 S; CHAR C2}; #pragma pack (POP) // Restore previous Pack settings When calculating SIZEOF (S1), the value of min (2, sizeof (i)) is 2, so the offset of i 2, plus SIZEOF (I) equal to 6, 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, can not be removed, add a padding byte, SIZEOF (S3) is equal to 10. Now, friends can easily take a breather, :) Other note, "empty structure" (excluding data member) 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); / / result is 1
8. SIZEOF of the domain structure has been said, the bitmaster member cannot be alone, and we will discuss the SizeOf of the structure containing the domain, just considering its specialty. Out. C99 specifies that int, unsigned int and bool can be used as a bit domain type, but the compiler extends almost all, allowing other types of types. The main purpose of the bit domain is to compress storage, and its approximate rules are: 1) If the type of neighbor domain field is the same, its bit width is smaller than the type of SizeOf size, the following fields will close adjacent to the previous field storage, Until until it does not accommodate; 2) If the type of neighbor domain field is the same, its bit width and larger than the type of SIZEOF size, the following field will start from the new memory cell, its offset is an integer of its type size Double; 3) If the type of adjacent bit field fields are different, the specific implementation of each compiler is different. VC6 takes no compression mode, DEV-C takes a compression method; 4) If the bit domain field is inserted into non-position The domain field is not compressed; 5) The total size of the entire structure is an integer multiple of the widest basic type member size. Or let's take a look at the example. Example 1: Struct Bf1 {Char F1: 3; Char F2: 4; CHAR F3: 5;}; its memory layout is: | _f1__ | __f2__ | _ | ____f3 ___ | ____ | | _ | _ | _ | _ | _ | _ | _ | _ | 0 3 7 8 13 16-bit domain types of char, the first byte can only accommodate F1 and F2, so F2 is Compressed into the first byte, and F3 can only start from the next byte. Therefore, the result of SIZEOF (BF1) is 2. Example 2: Struct BF2 {Char F1: 3; Short F2: 4; CHAR F3: 5;}; Due to the difference between adjacent bit domain, it is 6 in VC6, 2 in DEV-C . Example 3: Struct BF3 {Char F1: 3; CHAR F2; CHAR F3: 5;}; Non-bit fields are inserted therein, and no compression is generated, and the size obtained in VC6 and DEV-C is 3.9. The SizeOf structure of the consort is sequentially in memory organization. The combined body is overlapping, and each member shares a memory, so the SizeOf of the entire consort is also the maximum of each member 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 u is equal to SIZEOF (S). Union u {INT I; CHAR C; S1 S;