Tag:Program
From: http://rabbitlzx.blogbus.com/logs/2006/03/2094407.html
1. What is sizeof
First, let's take a look at the definition of sizeof on msdn:
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.
When I saw the word "return", did I think of a function? Wrong. sizeof is not a function. Have you ever passed parameters to a function without brackets? Sizeof is acceptable, so sizeof is not a function. Some people on the Internet say that sizeof is a unary operator, but I don't think so, because sizeof is more like a special macro, Which is evaluated during the compilation stage. For example:
Cout <sizeof (INT) <Endl; // the length of an int on a 32-bit machine is 4.
Cout <sizeof (1 = 2) <Endl; // = Operator returns the bool type, equivalent to cout <sizeof (bool) <Endl;
It has been translated:
Cout <4 <Endl;
Cout <1 <Endl;
Here is a trap. Let's look at the following program:
Int A = 0;
Cout <sizeof (A = 3) <Endl;
Cout <A <Endl;
Why is the output 4 or 0 instead of the expected 4 or 3 ??? It lies in the features of sizeof processing in the compilation phase. Because sizeof cannot be compiled into machine code, the content in the scope of sizeof, that is, (), cannot be compiled, but replaced with the type. = Operator returns the type of the left operand, so a = 3 is equivalent to int, and the code is replaced:
Int A = 0;
Cout <4 <Endl;
Cout <A <Endl;
Therefore, sizeof cannot support chained expressions, which is different from the unary operator.
Conclusion: Do not treat sizeof as a function, or a mona1 operator, and treat it as a special compilation preprocessing.
2. sizeof usage
Sizeof has two usage methods:
(1) sizeof (object)
That is, the sizeof object can also be written as a sizeof object.
(2) sizeof (typename)
That is to say, sizeof is used for the type. In this case, it is invalid to write sizeof typename. The following are examples:
Int I = 2;
Cout <sizeof (I) <Endl; // sizeof (object) usage, reasonable
Cout <sizeof I <Endl; // sizeof object usage, reasonable
Cout <sizeof 2 <Endl; // 2 is parsed to an int-type object. The usage of sizeof object is reasonable.
Cout <sizeof (2) <Endl; // 2 is resolved to an int-type object. The usage of sizeof (object) is reasonable.
Cout <sizeof (INT) <Endl; // sizeof (typename) usage, reasonable
Cout <sizeof int <Endl; // error! For operators, you must add ()
We can see that adding () is always the right choice.
Conclusion: It is best to add () regardless of the value of sizeof ().
3. sizeof of Data Type
(1) Inherent Data Types of C ++
The basic data type in 32-bit C ++, that is, Char, short int (short), Int, long int (long), float, double, long double
The values are: 1, 2, 4, 4, 8, and 10.
Consider the following code:
Cout <sizeof (unsigned INT) = sizeof (INT) <Endl; // equal, output 1
Unsigned only affects the meaning of the highest bit, and the data length will not be changed.
Conclusion: Unsigned does not affect the value of sizeof.
(2) Custom Data Types
Typedef can be used to define the C ++ custom type. Consider the following questions:
Typedef short word;
Typedef long DWORD;
Cout <(sizeof (short) = sizeof (Word) <Endl; // equal, output 1
Cout <(sizeof (long) = sizeof (DWORD) <Endl; // equal, output 1
Conclusion: the sizeof value of the custom type is the same as that of the original type.
(3) Function Type
Consider the following questions:
Int F1 () {return 0 ;};
Double F2 () {return 0.0 ;}
Void F3 (){}
Cout <sizeof (F1 () <Endl; // the return value of F1 () is int, so it is considered as int
Cout <sizeof (F2 () <Endl; // the return value of F2 () is double, so it is considered as double.
Cout <sizeof (F3 () <Endl; // error! Unable to use sizeof for void type
Cout <sizeof (F1) <Endl; // error! Unable to use sizeof for function pointer
Cout <sizeof * F2 <Endl; // * F2, equivalent to F2 (), because it can be viewed as an object, parentheses are not necessary. Is considered double
Conclusion: When sizeof is used for a function, it will be replaced by the type of the function return value in the compilation phase.
4. pointer Problems
Consider the following questions:
Cout <sizeof (string *) <Endl; // 4
Cout <sizeof (int *) <Endl; // 4
Cout <sizof (char ***) <Endl; // 4
As you can see,No matter what type of pointer, the size is 4, because the pointer is a 32-bit physical address.
Conclusion: The pointer size is 4. (64-bit hosts cannot be 8 ).
By the way, the pointer in C ++ indicates the actual memory address. Unlike C, C ++ removes the pattern, that is, there is no small, middle, or big, and it is replaced by a unified flat. The flat mode uses 32-bit real address addressing, instead of the segment: offset mode in C. For example, if there is a pointer pointing to the address f000: 8888, and if it is C type, it is 8888 (16 bits, only store the displacement, omitted segments ), far Type C pointer is f0008888 (32-bit, high reserved segment address, position reserved displacement), c ++ type pointer is f8888 (32-bit, it is equivalent to segment address * 16 + displacement, but the addressing range must be larger ).
5. array Problems
Consider the following questions:
Char A [] = "abcdef ";
Int B [20] = {3, 4 };
Char C [2] [3] = {"AA", "BB "};
Cout <sizeof (a) <Endl; // 7
Cout <sizeof (B) <Endl; // 20 ??? 80
Cout <sizeof (c) <Endl; // 6
The size of array A is not specified during definition. The space allocated to it during compilation is determined according to the initialization value, that is, 7. C is a multi-dimensional array, and the space occupied is the product of each dimension, that is, 6. As you can see,The size of the array is the space allocated during compilation, that is, the product of each dimension * the size of the array element.
Conclusion: The size of an array is the product of all dimensions * the size of an array element.
There is a trap:
Int * D = new int [10];
Cout <sizeof (d) <Endl; // 4
D is a dynamic array we often call, but it is actually a pointer, so the value of sizeof (d) is 4.
Consider the following questions:
Double * (* A) [3] [6];
Cout <sizeof (a) <Endl; // 4
Cout <sizeof (* A) <Endl; // 72
Cout <sizeof (** A) <Endl; // 24
Cout <sizeof (*** A) <Endl; // 4
Cout <sizeof (*** A) <Endl; // 8
A is a very strange definition, which indicates a pointer to an array of the double * [3] [6] type. Since it is a pointer, sizeof (a) is 4.
Since a is a pointer of the double * [3] [6] type, * a indicates a multi-dimensional array of the double * [3] [6] type. Therefore, sizeof (*) = 3*6 * sizeof (double *) = 72. Similarly, ** A indicates an array of the double * [6] type, so sizeof (** A) = 6 * sizeof (double *) = 24. * ** A indicates an element, that is, double *. Therefore, sizeof (*** A) = 4. As for *** A, it is a double, so sizeof (*** A) = sizeof (double) = 8.
6. array passing to Functions
Consider the following questions:
# Include <iostream>
Using namespace STD;
Int sum (int I [])
{
Int sumofi = 0;
For (Int J = 0; j <sizeof (I)/sizeof (INT); j ++) // actually, sizeof (I) = 4
{
Sumofi + = I [J];
}
Return sumofi;
}
Int main ()
{
Int allages [6] = {21, 22, 22, 19, 34, 12 };
Cout <sum (allages) <Endl;
System ("pause ");
Return 0;
}
Sum is used to get the size of the array with sizeof, and then sum. But in fact, the Input Self-function Sum is only a pointer of the int type, so sizeof (I) = 4, not 24, so it will produce an error. To solve this problem, use a pointer or reference.
Pointer usage:
Int sum (INT (* I) [6])
{
Int sumofi = 0;
For (Int J = 0; j <sizeof (* I)/sizeof (INT); j ++) // sizeof (* I) = 24
{
Sumofi + = (* I) [J];
}
Return sumofi;
}
Int main ()
{
Int allages [] = {21, 22, 22, 19, 34, 12 };
Cout <sum (& allages) <Endl;
System ("pause ");
Return 0;
}
In this sum, I is a pointer to the I [6] type. Note that int sum (INT (* I) []) cannot be used to declare a function, instead, you must specify the size of the array to be passed in. Otherwise, sizeof (* I) cannot be calculated. However, in this case, it is meaningless to use sizeof to calculate the array size, because the size is set to 6.
The reference is similar to the pointer:
Int sum (INT (& I) [6])
{
Int sumofi = 0;
For (Int J = 0; j <sizeof (I)/sizeof (INT); j ++)
{
Sumofi + = I [J];
}
Return sumofi;
}
Int main ()
{
Int allages [] = {21, 22, 22, 19, 34, 12 };
Cout <sum (allages) <Endl;
System ("pause ");
Return 0;
}
In this case, sizeof calculation is meaningless. Therefore, an array is used as a parameter. When traversal is required, the function should have a parameter to describe the size of the array, the size of the array is evaluated by sizeof within the scope defined by the array. Therefore, the correct form of the above function should be:
# Include <iostream>
Using namespace STD;
Int sum (int * I, unsigned int N)
{
Int sumofi = 0;
For (Int J = 0; j <n; j ++)
{
Sumofi + = I [J];
}
Return sumofi;
}
Int main ()
{
Int allages [] = {21, 22, 22, 19, 34, 12 };
Cout <sum (I, sizeof (allages)/sizeof (INT) <Endl;
System ("pause ");
Return 0;
}
7. String sizeof and strlen
Consider the following questions:
Char A [] = "abcdef ";
Char B [20] = "abcdef ";
String S = "abcdef ";
Cout <strlen (a) <Endl; // 6, String Length
Cout <sizeof (a) <Endl; // 7, string capacity
Cout <strlen (B) <Endl; // 6, String Length
Cout <strlen (B) <Endl; // 20, string capacity
Cout <sizeof (s) <Endl; // 12, which does not represent the length of the string, but the size of the string class
Cout <strlen (s) <Endl; // error! S is not a character pointer.
A [1] =' ';
Cout <strlen (a) <Endl; // 1
Cout <sizeof (a) <Endl; // 7, sizeof is constant
Strlen is the number of characters starting from the specified address to the first zero. It is executed in the running stage, and sizeof is the data size, here is the string capacity.Therefore, the sizeof value is constant for the same object. String is a C ++ string. It is a class. Therefore, sizeof (s) indicates not the length of a string, but the size of a string. Strlen (s) is wrong at all, because the strlen parameter is a character pointer. If you want to use strlen to get the length of the S string, you should use sizeof (S. c_str (), because the string member function c_str () returns the first address of the string. In fact, the string class provides its own member functions to obtain the capacity and length of the string, namely capacity () and length (). String encapsulates string operations, so it is best to use string to replace C-type strings during C ++ development.
8. view the CPU peer bounds from the sizeof problem of union
Consider the following: (default alignment)
Union u
{
Double;
Int B;
};
Union U2
{
Char A [13];
Int B;
};
Union U3
{
Char A [13];
Char B;
};
Cout <sizeof (u) <Endl; // 8
Cout <sizeof (U2) <Endl; // 16
Cout <sizeof (U3) <Endl; // 13
We all know that the size of Union depends on the size of one member that occupies the largest space among all its members. So for u, the size is the largest double type member A, so sizeof (u) = sizeof (double) = 8. However, for U2 and U3, the maximum space is an array of char [13] type. Why is the size of U3 13 and that of U2 16? The key lies in the member int B in u2. Because of the existence of int type members, the U2 alignment is changed to 4. That is to say, the U2 size must be 4 to the world, therefore, the occupied space is changed to 16 (the nearest 13 peer ).
Conclusion: The alignment of composite data types, such as Union, struct, and class, is the alignment of the members with the largest alignment.
By the way, the 32 C ++ uses eight-bit bounds to increase the running speed. Therefore, the compiler tries its best to put the data in the world to improve the memory hit rate. The field can be changed. The # pragma pack (x) macro can be used to change the method of the compiler's field. The default value is 8. C ++ is a smaller method than its own size. For example, if you specify that the compiler is bounded by 2 pairs and the size of the int type is 4, the int pair is bounded by 2 and 2, which is smaller than 4. In the default method, because almost all data types are not greater than the default method 8 (except long double ), therefore, all inherent types of peer methods can be considered as the size of the type itself. Change the above program:
# Pragma pack (2)
Union U2
{
Char A [13];
Int B;
};
Union U3
{
Char A [13];
Char B;
};
# Pragma pack (8)
Cout <sizeof (U2) <Endl; // 14
Cout <sizeof (U3) <Endl; // 13
Because the method of Manually changing to 2 is also changed to 2 for int, and the biggest Member for U2 is 2, so now sizeof (U2) = 14.
Conclusion: C ++'s inherent type of bounded access Compiler's bounded access method is smaller than its own size.
|
9. sizeof problem of structThe sizeof structure becomes more complex due to alignment problems, Take the following example: (the default alignment mode) struct S1 {char a; Double B; int C; char D ;}; struct S2 {char a; char B; int C; double D ;}; cout <sizeof (S1) <Endl; // 24 cout <sizeof (S2) <Endl; // 16 It is also two Char Types, one int type and one double type, Due to peer problems, their sizes are different. You can use Element Manipulation: first, the CPU determines the peer bounds of the struct, According to the conclusion in the previous section, both S1 and S2 take the largest element type, that is Double type. Then, each element is placed. For S1, first place a to the peer field of 8, assuming that it is 0, then the next idle address Is 1, but the next Element D is of the double type. To put it in the world of 8, leave 1 The closest address is 8, so d is placed in 8, and the next idle address becomes After 16, the peer interface of the next element C is 4 or 16, so C is placed in 16, At this time, the next idle address is changed to 20, and the next Element D needs to be bounded by 1, which is exactly So D is placed in 20, and the struct ends at 21. Because S1 So the space from 21-23 is retained, and the size of S1 is changed 24. For S2, first place a to the peer field of 8, assuming that it is 0, then the next idle address Is 1, the peer interface of the next element is also 1, so B is placed in 1, and the next idle address It is changed to 2; the peer interface of the next element C is 4, so take the address closest to 2 4 and place it in C, The next idle address is changed to 8, and the peer field of the next Element D is 8, so d is placed in 8, After all the elements are placed, the struct ends at 15 points, occupying 16 of the total space. Is a multiple of 8. There is a trap here. For struct members in the struct, do not consider it Alignment is his size. See the following example: struct S1 {char a [8] ;}; struct S2 {double D ;}; struct S3 {S1 S; char A ;}; struct S4 {S2 s; char a ;}; cout <sizeof (S1) <Endl; // 8 cout <sizeof (S2) <Endl; // 8 cout <sizeof (S3) <Endl; // 9 cout <sizeof (S4) <Endl; // 16; Although the S1 and S2 sizes are both 8, the S1 alignment is 1, S2 is 8 (double ), So there is such a difference between S3 and S4. Therefore, when you define a struct, if the space is insufficient, consider Alignment Elements in the struct.10. Do not let double interfere with your bit domainIn struct and class, you can use a bit field to specify the space occupied by a Member, Therefore, the space occupied by the struct can be saved to some extent by using the bit domain. However, consider the following code: struct S1 {int I: 8; Int J: 4; Double B; int A: 3 ;}; struct S2 {int I; Int J; double B; int A ;}; struct S3 {int I; Int J; int A; Double B ;}; struct S4 {int I: 8; Int J: 4; int A: 3; Double B ;}; cout <sizeof (S1) <Endl; // 24 cout <sizeof (S2) <Endl; // 24 cout <sizeof (S3) <Endl; // 24 cout <sizeof (S4) <Endl; // 16 you can see, if double exists, it will interfere with the sizeof algorithm reference. So when using the bitfield, it is best to set the float type and double Type at the beginning or end of the program. ------------------------------------------------------------ ------------------------------------------------------------ Sizeof's usage in Structure Calculation and sizeof's main usage Tag:Program
This article consists of two parts. The first part focuses on how to use sizeof in VC to find the structure size and problems that are prone to, and provides solutions to the problems, the second part summarizes the main usage of sizeof in VC.
1. Structure of sizeof applications
See the following structure:
Struct mystruct
{
Double dda1;
Char DDA;
Int type
};
What will happen if sizeof is used for the structure mystruct? What is sizeof (mystruct? You may ask:
Sizeof (mystruct) = sizeof (double) + sizeof (char) + sizeof (INT) = 13
However, when the above structure is tested in VC, you will find that sizeof (mystruct) is 16. Do you know why such a result is obtained in VC?
In fact, this is a special processing of variable storage by VC.To increase the CPU storage speed, VC performs "alignment" on the starting addresses of some variables.By default, VC specifies that the offset of the starting address of each member variable to the starting address of the structure must be a multiple of the bytes occupied by the variable type. Common alignment types are listed below (vc6.0, 32-bit system ).
Type Alignment (offset of the starting address of the variable to the starting address of the structure)
Char The offset must be a multiple of sizeof (char), that is, 1.
Int The offset must be a multiple of sizeof (INT), that is, 4.
Float The offset must be a multiple of sizeof (float), that is, 4.
Double The offset must be a multiple of sizeof (double), that is, 8.
Short The offset must be a multiple of sizeof (short), that is, 2.
When each member variable is stored, the space is requested in sequence based on the order in which the structure appears, and the positions are adjusted according to the alignment above. The vacant byte VC is automatically filled. At the same timeTo ensure that the size of the structure is a multiple of the byte boundary count of the structure (that is, the number of bytes occupied by the Type occupying the maximum space in the structure, therefore, after applying for space for the last member variable, the vacant bytes will be automatically filled as needed..
The following uses the previous example to illustrate how VC stores the structure.
Struct mystruct
{
Double dda1;
Char DDA;
Int type
};
When allocating space for the above structure, VC allocates space for the first member dda1 according to the sequence and alignment of the member variables, the starting address is the same as the starting address of the structure (the offset 0 is just a multiple of sizeof (double). The member variable occupies eight bytes; next, allocate space for the second member DDA. the offset of the next address that can be allocated to the starting address of the structure is 8, which is a multiple of sizeof (char, therefore, the DDA is stored in an alignment where the offset is 8. This member variable occupies sizeof (char) = 1 byte, and then allocates space for the third member type, in this case, the offset of the next allocable address to the starting address of the structure is 9, not a multiple of sizeof (INT) = 4. To meet the offset constraints of alignment, VC automatically fills in three bytes (these three bytes do not have anything). At this time, the next address that can be allocated has a 12 offset to the starting address of the structure, which is exactly sizeof (INT) = a multiple of 4, so the type is stored in the offset Where the value is 12, the member variable occupies sizeof (INT) = 4 bytes. At this time, the member variables in the entire structure have been allocated space, and the total occupied space is: 8 + 1 + 3 + 4 = 16, which is exactly the number of bytes in the structure (that is, the number of bytes occupied by the Type occupying the maximum space in the structure sizeof (double) = 8) so there is no vacant byte to fill. Therefore, the size of the entire structure is sizeof (mystruct) = 8 + 1 + 3 + 4 = 16. Among them, three bytes are automatically filled by VC and nothing makes sense.
Next, let's take another example to change the position of the member variable of mystruct above to the following:
Struct mystruct
{
Char DDA;
Double dda1;
Int type
};
How much space does this structure occupy? In the vc6.0 environment, we can obtain that sizeof (mystruc) is 24. Based on the space allocation principles mentioned above, we will analyze how VC allocates space for the above structure. (Simple description)
Struct mystruct
{
Char DDA; // The offset is 0. The alignment is satisfied and the DDA occupies 1 byte;
Double dda1; // the offset of the next available address is 1, not sizeof (double) = 8
// Multiple. You need to add 7 bytes to make the offset 8 (the alignment is satisfied ).
// Method). Therefore, VC automatically fills in 7 bytes, and dda1 is stored at an offset of 8
// Address, which occupies 8 bytes.
Int type; // the offset of the next available address is 16, which is twice that of sizeof (INT) = 4.
// Number, which meets the alignment of int, so no VC auto-fill is required.
// Put the address at the offset of 16, which occupies 4 bytes.
}; // All member variables are allocated space. The total size of the space is 1 + 7 + 8 + 4 = 20, not a structure.
// Number of knots (that is, the number of bytes occupied by the largest space type in the structure sizeof
// (Double) = 8), so four bytes need to be filled to meet the structure size
// Sizeof (double) = a multiple of 8.
Therefore, the total size of this structure is: sizeof (mystruc) is 1 + 7 + 8 + 4 + 4 = 24. Among them, 7 + 4 = 11 bytes are automatically filled by VC, and nothing makes sense.
The special processing of the structure storage by VC does increase the speed of the CPU storage variable, but sometimes it also brings some trouble. We also shield the default alignment of the variables, you can set the alignment of variables.
VC provides# Pragma pack (n) to set the variable to n-byte alignment. N-byte alignment means the offset of the Start address of the variable. First, if n is greater than or equal to the number of bytes occupied by the variable, the offset must meet the default alignment mode, second, if n is less than the number of bytes occupied by the variable type, the offset is a multiple of N, and the default alignment is not required. The total size of the structure also has a constraint, which is divided into the following two cases: if n is greater than the number of bytes occupied by all member variable types, the total size of the structure must be a multiple of the space occupied by the largest variable;
Otherwise, it must be a multiple of N. The following is an example of its usage.
# Pragma pack (push) // save alignment status
# Pragma pack (4) // set to 4-byte alignment
Struct Test
{
Char M1;
Double M4;
Int m3;
};
# Pragma pack (POP) // restore alignment
The size of the above structure is 16. Next we will analyze its storage situation. First, we will allocate space for M1, and its offset is 0, which meets our own alignment (4-byte alignment ), m1 occupies 1 byte. Then we start to allocate space for M4. At this time, the offset is 1 and three bytes need to be supplemented. In this way, the offset must be a multiple of N = 4 (because sizeof (double) is greater than N ), m4 occupies 8 bytes. Then allocate space for M3. At this time, the offset is 12, which must be a multiple of 4. m3 occupies 4 bytes. At this time, space has been allocated for all member variables. A total of 16 bytes are allocated, which is a multiple of N. If you change # pragma pack (4) to # pragma pack (16), the size of the structure is 24. (Please analyze it by yourself)
2. sizeof usage Summary
In VC, sizeof has many usage and may cause some errors. Next, we will summarize the usage of sizeof based on the parameters following sizeof.
A. the parameter is a data type or a common variable.For example, sizeof (INT) and sizeof (long. In this case, it should be noted that the results of different system systems or compilers may be different. For example, the int type occupies 2 bytes in a 16-bit system and 4 bytes in a 32-bit system.
B. the parameter is an array or pointer.The following is an example.
Int A [50]; // sizeof (A) = 4*50 = 200; calculates the space occupied by the array.
Int * A = new int [50]; // sizeof (A) = 4; A is a pointer, and sizeof (a) is the pointer size. In a 32-bit system, of course, it occupies 4 bytes.
C. The parameter is a structure or class.The processing of sizeof applications in the class and structure is the same. But there are two requirements:Note:First, static members in the structure or class do not affect the structure or class size, because the storage location of static variables is irrelevant to the instance address of the structure or class.
Second, the structure without member variables or the size of the class is 1, because each instance of the structure or class must have a unique address in the memory.
The following is an example,
Class test {int A; static double c}; // sizeof (TEST) = 4.
Test * s; // sizeof (S) = 4, and S is a pointer.
Class test1 {}; // sizeof (test1) = 1;
D. The parameter is other.The following is an example.
Int func (char s [5]);
{
Cout < // When the array parameter is passed, the system processes it as a pointer, so sizeof (s) is actually the pointer size.
Return 1;
}
Sizeof (func ("1234") = 4 // because the return type of func is int, it is equivalent to sizeof (INT ).
The above is the basic usage of sizeof. In actual use, pay attention to the analysis of the allocation policy of VC allocation variables, so as to avoid some errors. |