C ++ from scratch (9) -- What is Structure

Source: Internet
Author: User

C ++ starts from scratch (9)

-- What is structure?

The first thing to do after obtaining an algorithm is to map resources into numbers, as mentioned above, "the type is the protocol used to explain the binary numbers in the memory." That is to say, a number corresponds to a piece of memory (which may be 4 bytes or 20 bytes ), the type of this number is additional information to tell the compiler how to compile machine commands to implement the operation when an operation statement (that is, an operator) is found for that memory. For example, if two char-type numbers are used for addition operators, the machine commands compiled by the compiler are different from those for two long-type numbers, that is, the so-called "how to interpret the binary number protocol in memory ". Due to different interpretation protocols, each type must have a unique identifier to indicate a difference, which provides strong semantics.

Typedef

Providing semantics means to reflect the meaning of this sentence or this piece of code in the human world as much as possible in the Code. For example, the previous article defines a cross-river scheme, which is represented by a char type, then, an array of char SLN [5] is defined to reflect the solution from the variable name. But obviously, people looking at the Code may not be able to see that SLN is the abbreviation of solution and then understand the significance of this variable. But more importantly, it seems like this is a red apple, and you know it is an apple, but it may also be a toy, CD, or something else, that is, the semantics to be embodied should be embodied by the type, rather than the variable name. That is, char cannot reflect the required semantics.
In this regard, C ++ provides a very meaningful statement-Type Definition Statement. The format is typedef <source type Name> <identifier> ;. <Source type Name> indicates an existing type name, such as char and unsigned long. The <identifier> is a casual name of a programmer. It complies with the identifier rules to express semantics. The preceding cross-river scheme can be as follows:
Typedef char solution; solution SLN [5];
The above is actually an alias solution for the type char, and then the solution is used to define the SLN to better reflect the semantics to increase the readability of the Code. In the previous article, the number of people on both sides of the Strait is mapped to Char [4]. To enhance the semantics, you can:
Typedef char personlayout [4]; personlayout oldlayout [2, 200];
Note that the above is typedef char personlayout [4]; instead of typedef char [4] personlayout; because the array modifier "[]" is next to the defined or declared identifier, the pointer modifier "*" is connected to the front, so typedef char * ABC [4]; but not typedef char [4] ABC *;, because the type modifier has a fixed position in the definition or declaration statement.
The preceding figure shows a better semantic representation than char oldlayout [200] [4]. But does it reduce programming speed due to increasing the type name or variable name to reflect the semantics? If the coding process is too long, you will find that the programming time is not spent on coding, but debugging. Therefore, do not avoid writing long variable names or type names. For example, in the Win32 Security SDK, the following function name is provided:
Bool convertsecuritydescriptortostringsecuritydescriptor (...);
Obviously, this function is used to convert the Security Descriptor type into text form to facilitate people to view the information in the security descriptor.
Note that typedef not only creates an alias for the type, but also creates an original type. When writing char * a, B;, the type of A is char *, and B is Char, rather than the expected char *. Because "*" is a type modifier here, it is independent of the declared or defined identifier, otherwise for char a [4], B ;, is B char [4]? That seriously does not conform to people's habits. The preceding char is called the original type. To make char * The original type, you can: typedef char * pchar; pchar a, B, * C [4];. Both A and B are char *, while C is Char ** [4], so there is no problem: Char ** Pa = & ;.

Structure

Again, consider why the previous article maps the number of people layout into char [4], because the number of people can be expressed by a char, and the number of people layout has four people, so char [4] is used. That is to say, if char [4] is used to define only one variable, it represents a person's number distribution, and the compiler allocates four bytes of space on the stack at a time, and each byte represents a person's number. Therefore, to show the number of merchants on the left side of the riverbank, you must enter a [0], and the number of servants on the left must be a [1]. The disadvantage is obvious. From a [0], it cannot be seen that it represents the number of merchants on the Left Bank, that is, the ing meaning (the Merchant number on the Left Bank is mapped to the content of the first byte in the memory block, which is interpreted in the complement code format) cannot be reflected in the Code, reducing the readability of the Code.
The above is actually the need for memory layout, that is, how to explain the binary numbers of each byte in the memory block. For this reason, C ++ proposes the type definition character "{}". It is a pair of braces dedicated to defining a type in a definition or declaration statement, called a custom type. That is, the memory layout can be customized when the type originally provided by C ++ cannot meet the requirements. The format is <type keyword> <name >{< declaration statement >= ...}. <Type keyword> there are only three keywords: struct, class, and union. The so-called structure is the original type defined by the Type definer when the <type keyword> is struct. Its type name is <Name>, it represents multiple declaration statements written in the braces below. The Defined variables are in a serial relationship (as described later), as follows:
Struct ABC {long a, * B; double C [2], D;} A, * B = &;
The above is a variable definition statement. For A, the compiler is required to allocate a 4 + 4 + 8*2 + 8 = 32-byte continuous memory block on the stack, then, bind the first address to a, and its type is structured custom type (Structure for short) ABC. For B, the compiler is required to allocate a 4-byte memory block, bind the first address to B, and its type is a pointer of the structure ABC.
When variables A and B are defined above, the structure ABC is defined by writing the type definition character "{}" in the definition statement. Then, you can use the type name ABC to define the variable as follows, you don't need to do that every time, that is:
ABC & C = A, D [2];
Now let's take a look at the above. First, the preceding statement defines six ing elements, with a and B mapped to two memory addresses respectively. The four variable declarations in braces also generate four variables named ABC: A, ABC: B, ABC: C, and ABC: D; the ing values are 0, 4, 8, and 24. Their types are long ABC:, long * ABC:, double (ABC: :) [2], and double ABC: :, indicating the offset. ABC: indicates a hierarchy, indicating "ABC", that is, ABC: A indicates the variable a defined in structure ABC. It should be noted that because C ++ is a strong type language, it also defines ABC: as a Type modifier, resulting in long * ABC: type, it indicates that the identifier it modifies is a member of the custom type ABC, called the offset type, and this type of number cannot be used separately (as described later ). Because the type shown here is not a function, the ing is not a memory address, but an offset value (as described in the next article ). Unlike before, numbers of the Offset type (that is, the above Type) cannot be calculated because the offset is a relative concept and no reference is given, that is, it cannot: ABC: A; ABC: C [1];. The latter is a serious error, because the array operator "[]" requires that the first is an array or pointer type, and here the ABC :: c is the offset of the double array structure ABC, not the array type.
Note that the offset 0, 4, 8, and 24 above is exactly the same as the offset formed by a, B, C, and D placement in the memory sequentially. This is also the modifier of the struct keyword, that is to say, the variables defined previously are in a serial relationship.
Why do we need to map the offset? That is, Why map a to zero-byte offset, and B to four-byte offset? Because semantics can be added to the offset. In the previous section, "The Merchant number on the Left Bank maps the content of the first byte in the memory block to be interpreted in the complement format" is actually the first address offset of the given memory block to 0 bytes. Now, if an identifier is bound to it, you can name it lefttrader to express its semantics.
Since all the variables defined above are of the Offset type, there is no allocation of memory to map with them, and they normally cannot be of the reference type, that is, struct AB {long a, & B ;}; it will be wrong (note that it is still possible to use the initialization list in the constructor to initialize AB: B, but it is meaningless in terms of semantics, and it seriously affects the meaning of the structure, and its implementation is equivalent to a pointer type member variable, so this series does not discuss it ). Note that the double (ABC: :) [2] type modifier "ABC:" is enclosed in parentheses, because the type operator rules are interpreted from left to right, "ABC:" is actually interpreted, but it must be placed on the left of the identifier, it is the same as the pointer modifier "*", so it must be enclosed in parentheses to indicate that it is last modified. Therefore, double (* ABCD: :) [2] and double (** ABCD: :) [2] are defined as follows:
Struct ABCD {double (* PD) [2]; double (** PPD) [2];};
However, it should be noted that "ABCD:" cannot be used directly, that is, double (* ABCD: PD) [2]; is incorrect. to define a variable of the Offset type, you must use the "{}" type definition to customize the type. Note that C ++ also allows such a type double (* ABCD: *) [2], which is called a member pointer, that is, the type is double (* ABCD ::) the pointer of [2] can be as follows:
Double (** ABCD: * pppd) [2] = & ABC: PPD, (** ABCD: ** ppppd) [2] = & pppd;
It is very strange to recall what the pointer type is. Only a number of the address type can have a pointer type, indicating that its binary representation, that is, the address, is directly returned without calculating the number of that address type. For a variable, the address is the number mapped to it, and the pointer directly returns the number mapped to it. Therefore, the number returned by & ABCD: PPD is actually an offset value, that is, 4.
To apply the preceding offset type, C ++ provides a pair of operators-member operators "." and "-> ". The former is connected to numbers on both sides, the left is the address type Number of the custom type, and the right is the offset type Number of the corresponding custom type, returns the number of the address type given in the offset type, for example,. ABC: D ;. The type of A on the left is ABC, and the type of ABC: D on the right is double ABC:, then. ABC: D returns a number of the double address type. Therefore,. ABC: D = 10.0 ;. Assume that the address of a is 3000, then. ABC: D returns the address 3000 + 24 = 3024 and the type is double. That is why ABC: D is called the offset type. Because the structure type on the left side of "." should be the same as the structure type on the right side, the above ABC: can be omitted, that is, a. d = 10.0 ;. For "->", like ".", the number on the left is pointer type, that is, B-> C [1] = 10.0 ;. Note that B-> C [1] is actually (B-> C) [1] rather than B-> (C [1]), because the latter uses "[]" for the offset type, it is wrong.
Pay attention to the following because of the Offset type on the right side:
Double (ABC: * pA) [2] = & ABC: C, (ABC: ** PPA) [2] = & PA;
(B-> ** PPA) [1] = 10.0; (A. * pA) [0] = 1.0;
The above brackets are added because the array operator "[]" has a higher priority than "*", but why not B-> (** PPA) [1] But (B-> ** PPA) [1]? The former is incorrect. Note that the brackets operator "()" does not change the calculation priority, but is also an operator. Its priority is set to a high value, and its calculation is to calculate the numbers in the brackets. Previously, it was also explained that the offset type cannot be calculated, that is, ABC: C; would be wrong, and the former was required to calculate the number of the Offset type due to the addition, therefore, the compiler reports an error.
It should also be noted that the member pointer is a pointer of the Offset type, that is, if it is installed with an offset, you can get an offset during the program running period, and the previous form obtained through ABC: A is the compilation period, the offset mapped by the compiler only supports static offset, while the member pointer can achieve dynamic offset. However, you only need to define members as arrays or pointer types to achieve dynamic offset, but it is the same as that in the previous article that no structure is used to map the number of people layout, which lacks semantics and is less readable. With the introduction of member pointers, variable names can demonstrate a wide range of semantics to enhance code readability. Now, we can define the people population layout as follows:
Struct personlayout {char lefttrader, leftservitor, righttrader, rightservitor ;};
Personlayout oldlayout [200], B;
Therefore, to represent the number of merchants on the left of B, only B. lefttrader; is required. The number of servants on the right needs B. rightservitor ;. Because personlayout: lefttrader records the offset value and the type of memory to be interpreted after the offset, the original B [0] and B [3] can be implemented above. Obviously, the former is much more readable than the latter, because it uses the variable name (B and personlayout: lefttrader) and the member operator ". "represents a large number of semantics-the number of merchants on the left of B.
Note: The personlayout: lefttrader is called a member variable of the structure personlayout, while the ABC: D is a member variable of the ABC. This call indicates that the structure defines a hierarchical relationship, the so-called member operator is also available. Since there are member variables, there are also member functions, which will be described in the next article.
In the previous article, we mapped the cross-river scheme to Char, where the first four represent the number of servants, and the last four represent the number of merchants. For this usage with a length less than 1 byte, C ++ provides a special syntax to support this situation, as shown below:
Struct solution {servitorcount: 4; unsigned tradercount: 4;} SLN [5];
Because the operation is based on the bit of the binary number, only two types are allowed to represent the number. The original code interprets the number or the complement code interprets the number. For the above, servitorcount is the complement explanation, while tradercount is the original code explanation, each of which has a length of 4 bits. At this time, solution: servitorcount still records the offset, however, it is not measured in bytes, but in bits. And because it has no type, there will be no member pointer. That is, in the previous article (SLN [cur [cursln] & 0xf0)> 4 is equivalent to SLN [cur [cursln]. tradercount, while SLN [cur [cursln] & 0xf0 is equivalent to SLN [cur [cursln]. servitorcount, which is more readable than before.
It should be noted that, Because struct AB {long a, B ;}; is also a statement and a declaration statement (because no code is generated), in its sense, generally, it is called a Definition Statement, indicating a Type Definition Statement. However, it is still a declaration statement based on the rules that do not generate code, and can be placed in the Type Definition "{}", namely:
Struct ABC {struct dB {long a, * B [2] ;}; long C; db ;};
The above structure dB is defined in the statement of structure ABC, then four variables are defined above, the types are all offset types, and the variable names are: ABC: DB :: a, ABC: DB: B, ABC: C, ABC: A; the types are long ABC: DB:, long * (ABC: DB: :) [2], long ABC:, and ABC: dB. The ing values are 0, 4, 0, and 4 in sequence. The structure dB is nested in the structure ABC, which shows a hierarchical relationship. In reality, this is often used to express specific semantics. To define a variable in the schema dB, ABC: db ;. Long * (ABC: DB: * pb) [2] = & ABC: DB: B; ABC C; C. a. A = 10; * (C. a. B [0]) = 20 ;. Note that ABC: DB: indicates "ABC's DB" instead of "DB's ABC", because here is a repeated Type modifier, it is modified from right to left.
In the previous definition of the structure, a type name is specified, such as ABC and ABCD. Note that the type name is not required, that is, you can use struct {long; double B;} A;. A = 10;. B = 34.32 ;. A variable is defined here, and its type is a structure type. However, this structure type has no identifier associated with it, so that it cannot be compared using the type matching, as shown below:
Struct {long a; Double B;} A, & B = A, * c = & A; struct {long a; Double B;} * D = &;
There is no problem with A, B, and C above, because the same type is used for definition, even if this type has no identifier ing with it, D will report an error, even if the subsequent structure definition is the same as the previous one, it is still not the same, but looks like it. So what is the purpose? It is described later.
At last, it should be noted that when the previous statement is written in a composite statement to define the structure, the variable scope mentioned earlier also applies, that is, the structure defined in a composite statement, the compound statement is deleted, which is not defined. As follows:
Void ABC ()
{
Struct AB {long a, B ;};
AB d; d. B = 10;
}
Void main ()
{
{
Struct AB {long A, B, E ;};
AB C; C. E = 23;
}
AB a; // an error will be reported, indicating that AB is undefined, but there is no other problem
}

Initialization

Initialization is to assign a value to the memory allocated on the stack while defining the variable, for example, long a = 10 ;. When the defined variable type represents multiple elements, such as the array type and the preceding structure type, multiple numbers are required. In this regard, C ++ provides a special syntax, which uses a pair of braces to enclose the value to be assigned, and then the whole is assigned to an array or structure as a number, as follows:
Struct ABC {long a, B; float c, d [3] ;};
Abc a = {1, 2, 43.4f, {213.0f, 3.4f, 12.4f }};
The above shows the initialization syntax for variable A. Braces enclose each element, and each element is separated by commas. Note that ABC: D is an array type, and the numbers used for initialization must be enclosed in braces. Therefore, the nested braces above appear. Now we should know that "{}" is only used to construct a number with multiple elements, so it can also be long a = {34 };, "{}" is equivalent to "no. It should also be noted that C ++ agrees to give less numbers than the number of elements of the corresponding custom type or array, that is, abc a = {1, 2, 34 }, B = {23, {34}, 65, {23, 43 }}, c = {1, 2, {3, {4, 5, 6 }}};
A. d [0],. d [1],. d [2] is 0, and only B. d [2] is 0, but C will report an error, because the first braces in the nest also include {4, 5, 6}, indicating C. C will be assigned a value by a number with two elements, but C. the C type is float and only corresponds to one element. The compiler will say there are too many initialization projects. The elements that are not assigned values of A and B will be assigned 0, but it should be noted that they are not 0 on the value, instead, the unassigned memory value is simply filled with 0, and then interpreted as a value in the format of the complement source code, which is exactly 0, rather than the value 0.
C ++ agrees with the Syntax: long a [] = {34, 34, 23 };. The number of elements is not given when a is defined. Instead, the compiler checks the number of elements in the braces used for the assignment and determines the number of arrays, therefore, the type of a above is long [3]. For multi-dimensional arrays, such as long a [3] [2] ={{ 1, 2}, {3, 4}, {5, 6 }};. Because each element requires numbers of multiple elements, it is the same as ABC: d in the previous section. Recall the type modifier's modifier order from left to right, but when it is a repeated Type modifier, It is reversed from right to left, therefore, the above should be three long [2] instead of two long [3], so the error will be: long a [3] [2] = {1, 2, 3 },{ 4, 5, 6 }};.
It should also be noted that C ++ not only provides the above "{}" initialization method, but also specifically provides strings such as char a [] = "ABC ";. Here, the type is Char [4], because the string "ABC" requires 4 bytes of memory space. In addition to the two initialization methods, C ++ also provides a function-based initialization function.

Application of Types

Char A =-34; unsigned char B = (unsigned char);
The above B is equal to 222, and-34 is written as the binary number 11011110 In the complement format. Then, the binary number is interpreted in the original code format and the value is 222. Continue:
Float a = 5.6f; unsigned long B = (unsigned long);
This time B is equal to 5. Why? Shouldn't 5.6 be written as a binary number 0x40b33333 (expressed in hexadecimal format) in IEEE real * 4 format, and then the binary number is interpreted as a value of 1085485875 in the original code format? Because type conversion is semantic type conversion, rather than type conversion.
Whether the two types can be converted depends on whether the compiler defines the conversion rules between the two types. For example, char and unsigned char are converted as before because the compiler defines Char to unsigned char, and float to unsigned long is defined by the compiler as an integer instead of rounding.
Why type conversion? What is the significance? Indeed, the conversion like above is meaningless, just to satisfy the rigor of the syntax. However, since C ++ defines the conversion of pointer types and is well defined, so that it has very important significance.
Char A =-34; unsigned char B = * (unsigned char *) (& );
The above result is the same as the previous one. B is 222, But it returns 222 by converting char * to unsigned char * And then interpreting the corresponding memory with unsigned char, instead of converting according to the compiler, even if the results are the same. Therefore:
Float a = 5.6f; unsigned long B = * (unsigned long *) (& );
The above B is 1085485875, Which is the result we thought previously. Here, the memory corresponding to the address a is interpreted using the rule defined by unsigned long. The result is put in B, which shows how the type is interpreted in memory. The above is implemented because C ++ specifies the conversion between all pointer types, and the numeric value of the number is not changed, only the type changes (but the inheritance relationship of the class may also change, the value of B is the result of unsigned long to explain the memory content of. Therefore, the previous article compares oldlayout [cursln] [0 ~ 3] and oldlayout [I] [0 ~ 3] write four "=" to compare the char numbers for four times. Since these four char numbers are stored consecutively, you can also compare the long numbers once as follows, this saves three additional comparisons.
* (Long *) & oldlayout [cursln] = * (long *) & oldlayout [I]
The above is only an optimization method, which does not have much meaning for semantics. However, because of the custom type, the following is true:
Struct AB {long A1; long A2 ;}; struct ABC {char a, B; short C; long d ;};
AB A = {53213,325 42}; ABC * pA = (ABC *) &;
Char AA = pa-> A, BB = pa-> B, Cc = pa-> C; long dd = pa-> D;
Pa-> A = 1; pa-> B = 2; pa-> C = 3; pa-> d = 4;
Long aa1 = A. A1, Aa2 = A. A2;
After the preceding execution, the values of AA, BB, CC, and DD are-35,-49, 0, and 32542 respectively, while the values of aa1 and Aa2 are 197121 and 4, respectively. I believe that I should be able to understand why I didn't modify. a1 and. a2, but their values change, because the variables are only a ing, and the previous step is to use the pointer Pa to explain and manipulate the memory content of A in structure ABC.
Therefore, using custom type and pointer conversion, you can view the content of a block of memory according to the rules. What is the purpose? A memory reference passed to a function (using the pointer type or reference type). This function also has another parameter, such as the long type. When the parameter of the long type is 1, it indicates that an order is passed in; if it is 2, it indicates that the order is sent in the past; if it is 3, it indicates a receipt ticket. If the enumerated types described below are matched, You can compile code with excellent semantics.
It should be noted that the pointer can be converted at will, and the following code has no practical significance. Here, we only need to deepen our understanding of the member pointer:
Long AB: * P = (long AB: *) (& ABC: B); A. A1 = A. A2 = 0; A. * P = 0xab1234cd;
After the above execution, A. A1 is 305450240, A. A2 is 171, and The hexadecimal format is 0x1234cd00 and 0x000000ab, respectively.

Enumeration

The switch or if statement can be used to determine if the order is 1 and 2 and 3 are the payment order, however, the statement can see from the Code such as type = 1 or type = 2, and does not show semantics. C ++ provides the enumeration type.
The enumerated type format is similar to the preceding custom type, but its meaning is completely different, as follows:
Enum AB {left, right = 2, up = 4, down = 3}; AB A = left;
Switch ()
{
Case left:; // perform the corresponding action on the left
Case up:; // do the relevant thing
}
Some identifiers must also be included in the enumeration. However, these identifiers do not map memory addresses or offsets, but map integers. Why are they integers, that is because there is no need to map floating point numbers. The above right is equivalent to 2. Note that it is equivalent to 2, which is equivalent to a name for 2. Therefore, long B = left; double C = up; char d = right; can be used ;. Note that the preceding variable A is of the AB type, that is, enumeration type. Its interpretation rules are equivalent to int, that is, compiled to run on a 16-bit operating system, the length is 2 bytes, And it is 4 bytes when compiled into a 32-bit operating system, but it is of a different type than int, and the previous value assignment operation is OK, it can be considered that the compiler will implicitly convert the enumeration type to the int type, and there is no error above. However, it won't work because the type of variable A is AB, and its value must be one of the four identifiers listed above, and a = B; then, because B is of the long type, if the value is 10, one of the above four identifiers cannot be mapped, so no.
Note that "=" is not written in the left column. In this case, the value of an identifier is automatically added to the value of the identifier. because it is the first identifier, the value of C ++ is set to 0, therefore, the left value is 0. Note that the numbers mapped above can be repeated:
Enum AB {left, right, up = 5, down, Top = 5, bottom };
The numbers mapped to the above identifiers are 0, 1, 5, 6, 5, and 6. Therefore, you can solve the problem as follows:
Enum operationtype {order = 1, invoice, checkout };
The parameter type can be operationtype, so that the semantics is far beyond the original code and the readability is much higher. Therefore, when we map some concepts of the human world into numbers, we find that their differences are not shown in numbers. For example, eating, sleeping, and playing represent a person's state, to map a person to a number, you also need to map the person's state to a number, but obviously there is no convenient ing rule. In this case, we forcibly say that 1 represents dinner, 2 represents sleep, and 3 represents play. Now we can define 1, 2, and 3 as enumeration to express semantics, that is why enumeration is defined only as an integer, because it is not necessary to define it as a floating point.

Union

As mentioned earlier, struct, class, and union can be connected before the type specifiers. When union is connected, it indicates a union-type custom type (Joint for short ), the difference between it and struct is that the latter defines member variables in Serial distribution, while the former is in parallel distribution. As follows:
Union AB {long A1, A2, A3; float B1, B2, B3 ;}; AB;
The length of variable A is 4 bytes, instead of 6*4 = 24 bytes. the offset of the ing of the six variables defined in the joint AB is 0. Therefore,. a1 = 10; after execution,. a1,. a2,. the value of A3 is 10, and. if the B1 value is, the IEEE real * 4 format is used to explain the content of the corresponding memory.
That is to say, we can use the pointer to explain the content of different memories. Now we can use the Union to complete the process. Therefore, the above Code is moved to the following:
Union AB
{
Struct {long A1; long A2 ;};
Struct {char a, B; short C; long d ;};
};
AB a ={ 53213,325 42 };
Char AA = A. A, BB = A. B, Cc = A. C; long dd = A. D;
A. A = 1; A. B = 2; A. C = 3; A. D = 4;
Long aa1 = A. A1, Aa2 = A. A2;
The results remain unchanged, but the code should be simple. Only one custom type is defined, and no pointer variable is used, so the semantics of the Code becomes more obvious.
Note that two structures are defined in the preceding definition of joint AB, but no names are assigned. This is a special usage of C ++. If you use a type definition character in the middle of a type definition character, if you do not bind an identifier to the type defined by the Type Definition character, the variables of the Offset type are still defined, however, these variables become member variables of the Upper-layer custom type. Therefore, "{}" is equivalent to "no, the unique significance is to use the previous struct, class, or union to specify the distribution of variables. Therefore, it can be as follows:
Struct AB
{
Struct {long a1, a2 ;};
Char A, B;
Union {float B1; double B2; struct {long B3; float B4; char B5 ;};};
Short C;
};
The preceding User-Defined AB member variables include A1, A2, A, B, B1, B2, B3, B4, B5, and C, the corresponding offset values are 0, 4, 8, 9, 10, 10, 10, 14, 18, and 19 respectively, and the total length of type AB is 21 bytes. The length of a certain type indicates how much continuous space the compiler should allocate to the stack if a variable is defined using this type. For this reason, C ++ provides a special operator sizeof, the right side is followed by a number or type name. When it is followed by a number, the size of the memory space required by the number type is returned, returns the size of the memory space of the type identified by the type name.
Therefore, long a = sizeof (AB); AB d; long B = sizeof D; after execution, the values of A and B are both 40. How is 40? Shouldn't it be 21? The offsets corresponding to the previous member variables are actually 0, 4, 8, 9, 16, 16, 16, 20, 24, and 32. Why? This is the so-called data alignment.
If the CPU has certain commands and multiple data needs to be processed, the interval between each data must be 4-byte, 8-byte, or 16-byte (depending on the instruction ), this is called data alignment. When the interval between data does not meet the requirements, the CPU must perform additional work to align the data, and the efficiency will decrease. In addition, the CPU does not directly read from the memory. Instead, it needs to be buffered by a high-speed buffer (a hardware with a built-in access speed faster than the memory, the buffer size must be the power of 2, but it is relatively small. Therefore, the size of the custom type is preferably a multiple of the power of 2, so that high-speed buffering can be used efficiently.
For a custom type, the offset value of a member variable must be a multiple of the length of the type to which it belongs, that is, the offset of A and B must be a multiple of 1, the offset of C must be a multiple of 2, and that of B1 must be a multiple of 4. However, the offset of B2 must be a multiple of 8, while the parallel layout of B1 and B2 is caused by the preceding Union. Therefore, the offset of B1 must be the same as that of B2 and B3, therefore, the offset of B1, B2, and b3 is 16, instead of 10.
The length of a custom type must be a multiple of the length of the member variable with the longest length in its member variable. Therefore, struct {long B3; float B4; char B5 ;}; the length is a multiple of 4, that is, 12. In the member variables of the Untitled union above, only double B2; has the longest length, which is 8 bytes, so its length is 16, in addition, the offset of C is 16 for B1, so it is 32. Because the member variable in the structure AB only has the longest length of B2 and is 8, the length of AB must be a multiple of 40 of 8. Therefore, when defining the structure, we should try to match the member length as follows:
Struct ABC1 {char a, B; char D; long c ;};
Struct abc2 {char a, B; long C; char D ;};
The length of ABC1 is 8 bytes, while that of abc2 is 12 bytes. The ing offset of ABC1: C and abc2: C is 4.
Note that the rules mentioned above can be changed through the compilation option. Different compilers will provide different modification methods, which are not listed here.
This article describes how to use the type definer "{}" to define a custom type. It describes two types of custom types. Many other types are not described in the next article, that is, the classes and class-related content described later can be applied to the Union and structure, because they are all custom types.

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.