C starts from zero (Nine) - What is the pre-structure of the structure that has been programmed, and the first thing to get after the algorithm is to map the resource into a number, and the "Type" is how people have explained memory. The binary protocol of the binary, that is, a number corresponding to a memory (possibly 4 bytes, or 20 bytes), and this number is additional information to tell the compiler When it is found to have the block How to write machine instructions when the memory operates statement (ie, some operator) to implement that operation. For example, the number of two char types performs an addition operator operation, the compiler is compiled with the machine instructions that are different from the number of two long types, which is the so-called "how to explain the binary number of binary numbers in memory". . Due to the difference in the interpretation protocol, each type must have a unique identifier to distinguish, this is prior to providing a strong semantic. Typedef provides semantics to reflect this sentence or this code in the code in the code, such as the previously defined cross-river program, using a char type, and define a array char SLN [ 5] This is a program from the name of the variable. However, it is obvious that people who see code can see that SLN is Solution abbreviation and thus understanding this variable. But more importantly, this is a bit of the original invert, as if this thing is a red apple, then know this thing is Apple, but it may be toys, CDs or others, that is, the semantics that need to be reflected should be reflected by the type, not variable name. That is, Char cannot reflect the semantics required. In this regard, C provides a meaningful statement - type definition statement. The format is typedef
Therefore, don't taboo writing long variable names or type names. For example, in the Win32 SECURITY SDK, it provides the following function name: BOOL ConvertSecurityDescriptORTSTRINGSECURITSCRIPTORTRINGSECURITESCRIPTOR (...); it is clear, this function is used to convert the security descriptor Text form is to facilitate people to view information in the security descriptor. It should be noted that typedef is not only an individual name to the type, but also created one original type. When writing char * a, b;, the type of A is char *, B is char, not imaginary char *. Because "*" is here a type modifier, it is an identifier independent of the declaration or defined, otherwise, for Char A [4], B ;. Is it a CHAR [4]? That is seriously inconsistent with people's habits. The above char is called the original type. In order to let Char * are original type, you can: typedef char * pchar; pchar a, b, * c [4]; Among them, A and B are char *, and C is char ** [4], so there is no problem: char ** pa = & a ;. Structure once again considering the previous article to map the number layout into char [4], because one of the numbers can be represented by a char, and the number of people has four people, so using char [4]. That is, use char [4], it is desirable to define a variable representing a number of people, and the compiler allocates 4 bytes of space on the stack, and each byte represents a number of people. Therefore, in order to express the number of business people on the left side of the river, you must write a [0], and the number of servants on the left must be A [1]. The disadvantages are obvious, from a [0] can't see it is the number of business people on the left bank, that is, this map meaning (the number of business people on the left bank is mapped to the first byte of the memory block, the complement format is unable to The code is reflected, which reduces the readability of the code. The above is actually the need to the memory layout, that is, how each byte binary number in the memory block is explained. To this end, C proposes type definitions "{}". It is a pair of braces, dedicated to define or declare statements to define a type, called a custom type. That is, the type of C original default cannot meet the requirements, you can customize the memory layout. The format is:
When the variables A and B are defined above, the structural ABC is defined by writing type definitions "{}" in the definition statement, and the type name ABC can be used as follows, without having to make each time, ie: ABC & C = a, d [2]; now to see the meaning of the above. First, the previous statement defines six mapping elements, where A and B are mapped to two memory addresses. The four variable declarations in braces also generate four variables, their names are abc :: A, abc :: b, abc :: c, abc :: d; each map is 0, 4, 8 And 24; their respective types are long ABCs ::, long * ABC ::, double (abc: :) [2], double abc ::, indicated is offset. ABC :: represents a hierarchical relationship, indicating "ABC", ie ABC :: A represents the variable A defined in the structure ABC. It should be noted that since C is a strong type language, it will define the ABC :: is also defined as a type modifier, which in turn leads to the type of long * ABC :: this, indicating that the identifier it is modified is a member of the custom type ABC, called The number of shifts, and this type of number cannot be used separately (later description). Since the type of appears here is not a function, it is not a memory address, but an offset value (hereinafter explained). Different from the previous, the type of offset type (ie, as the above type) number is not calculated, because the offset is a relative concept, no reference is unable to produce any meaning, that is,: ABC :: A; ABC :: C [1] ;. Among them, the latter is more serious, because the array operator "[]" requires the array or pointer type, and the ABC :: C here is the offset in the archive of the array type of ABC, is not an array Types of. Note that the offset of the above offset is equal to the offset formed in the memory, which is also the modification of the keyword of the struct, which is the so-called modification of this keyword. The defined variables are serial relationships. Why do you want to make mappings to the offset? That is, why is A map into an offset 0 byte, B map into offset 4 bytes? Semanity is added to the offset. The front "The number of business people on the left bank is mapped to the first byte in the memory block," in the completion of the format "is actually a given memory block of the first address offset 0 byte. Now give an identifier and its binding, this identifier can be called LEFTTRADER to express its semantics. Since the variables defined above are offset types, there is no distribution in the allocation to create mappings, which are often unable to reference type, namely struct ab {long a, & b;}; will be wrong (pay attention to actual Also, by initializing AB:: B by using an initialization list in a constructor, it is meaningless, and it has seriously affects the meaning of the structure, and its implementation is equivalent to a member variable of a pointer type. The series does not discuss it). It should also be noted that the type Double (abc ::) [2] above, the type modifier "ABC ::" is enclosed in parentheses, as the rules of the type operator are interpreted according to the left to right, "ABC ::" actual It should be finally interpreted, but it must be placed on the left side of the identifier, just like the pointer modifier "*", so it must be hosted by brackets to indicate that it is finally modified.
Therefore, there is: Double (* abcd ::) [2], double (** abcd ::) [2], each as defined: struct abcd {double (* pd) [2]; double; ** PPD) [2];};,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, "{}" Is from the defined type. It should also be noted that C also allows such types Double (* ABCD:: *) [2], which is called member pointer, ie the type of Double (* ABCD ::) [2], that is, as follows: Double (** abcd :: * pppd) [2] = & abc :: ppd, (** abcd :: ** pppd) [2] = & PPPD; it is very strange to think about what is the pointer type. Only the number of the address type can have a pointer type, indicating that the number of the address type is not calculated, and directly returns its binary representation, that is, the address. For variables, the address is the number it maps, and the pointer represents the number directly returns to its mapping, so the number of the reference returned by the & abcd :: PPD is actually a offset value, that is, 4. In order to apply the above offset type, C gives a pair of operators - member operators "." And "->". The former two-side digit, the left is connected to the number of address types of the type of address, and the right side is connected to the number of offset types of the corresponding type, returns the number of address types of the type given in the offset type, such as: a.abc :: D ;. The type of the left A is ABC. The type of ABC :: D on the right is Double ABC ::, then the number of A.abc:d returned is the number of Double's address type, so that you can: a.abc :: D = 10.0 ;. Assuming that a correspondence is 3000, then a.abc :: Returned the address of 3000 24 = 3024, the type is Double, which is why ABC :: D is called the offset type. Since "." The structure type of the left should be the same as the same type of structure, so the above ABC :: can be omitted, namely A.d = 10.0; For "->", and ".", Only the numbers of the left are the type of pointer, that is, B-> C [1] = 10.0; Note that B-> C [1] is actually (b-> c) [1], not B-> (C [1]), because the latter is the use of offset type "[]", it is wrong . It should also be noted that due to the number of the offset type, you can be as follows: double (abc :: * pa) [2] = & abc :: c, (abc :: ** ppa) [2] = & pa; (b- > ** PPA) [1] = 10.0; (a. * pa) [0] = 1.0; the above is to be added to be because the priority of the array operator "[]" is higher than "*", but why not B -> (** ppa) [1] but (b -> ** ppa) [1]? The former is wrong. Note that parentheses operators () "are not changed to calculate priority, but it also acts as an operator, and its priority is set to be very high, and its calculation is to calculate the numbers in parentheses. It also illustrates that the offset type cannot be calculated, ie ABC :: C; the incorrect, and the former former "()" is required to calculate the number of the offset type, so the compiler will report an error.
It should also be noted that the member pointer is a pointer of the offset type, that is, the offset can be installed, then the program is running offset, and the previous form is compiled in the form of the compiler, it is called by the compiler. The offset can only achieve static offset, and dynamic offsets can be realized by using member pointers. However, it is actually required to define a member or a pointer type to achieve dynamic offsets, but it is not the same as the previous article without using structural samples, which is low, and the code readability is low. The presenter of the member pointer can exhibit a rich semantics through the variable name to enhance the readability of the code. Now, you can define the most beginning of the number of people: struct personLayout {Char LeftTrader, LeftServitor, RightTrader, RightServitor;}; PersonLayout OldLayout [200], B; So, in order to represent b, the number of people in this number of people, Just b.lefttrader;, the number of servants on the right, only b.rightservitor ;. Because the PersonLayout :: LeftTrader records what type of memory should be explained after the offset is recorded, the original B [0] and B [3] can be implemented above. Obviously, the former readability is far higher than the latter because the former has passed the variable name (B and PersonLayout :: LeftTrader) and member operators "." The number of business people on the left side of the semantic-B is shown. Note PersonLayout :: LeftTrader is called the member variable of the structure of PersonLayout, and the front ABC :: D is the member variable of ABC, which defines a hierarchical relationship, and has a so-called member operator. Since there is a member variable, there is also a member function, which is introduced in the next sheet. The previous article mapped to Char when mapping the river program, where the top 4 represents the number of servants, and the last 4 represents the number of people. For this type of use of less than one byte, C provides a syntax to support this situation, as follows: struct solution {servitorcount: 4; unsigned tradercount: 4;} SLN [5]; due to binary The number of bit (BIT) is operated, only two types are used to represent numbers, the original code interpret numbers or complement numbers. For the above, servitorcount is the complement interpretation, and tradercount is the original code explanation, and the respective length is 4 digits, and the Solution :: ServitorCount is still the offset, but no longer in bytes, but Bit is in units. And because there is no type, there is no member pointer. That is, the previous article (SLN [CUR [CURSLN]] & 0xF0) >> 4 is equivalent to SLN [cur [cursln]] .tradercount, and SLN [cur [cursln]] & 0xf0 is equivalent to SLN [cur [cursln] ] .Servitorcount, which has better readability than before.
It should be noted that due to struct ab {long a, b;}; is also a statement, and is a declarative statement (because does not generate code), but in its sense, more often called it a definition statement, indicating Is the type definition statement, but according to the rules that do not generate the code, it is still a statement statement, and it can be placed in the type definition "{}", namely: struct abc {struct db {long A, * b [2 ];}; long C; DB A;}; The above structure DB defines that the four variables are defined in the declaration statement of the structure ABC, and the type is the offset type, and the variable name is: ABC :: DB :: A, abc :: db :: b, abc :: c, abc ::;; type 依 on on: :: dB ::, long * (abc :: db ::) [2], long abc ::, abc :: db; the value of the map is 0, 4, 0, 4. Here, the structure DB is nesting in structure ABC, which reflects a hierarchical relationship, which is often used in the actual use to express specific semantics. To define a variable with the structure DB, ABC :: DB A; Also there is a long * (abc :: db :: * pb) [2] = & abc :: db :: b; abc C; c.a.a = 10; * (C.A.B [0]) = 20; Note that ABC :: DB :: Represents "ABC's DB" rather than "ABC of DB" because it is a repetitive type modifier, which is modified from right to left. When the structure is defined in front, a type name is indicated, as in front of ABC, ABCD, etc., but should pay attention to the type name is not necessary, that is, can struct {long a; double b;} a; AA = 10; AB = 34.32 ;. A variable is defined here, which is a struct type, but this structural type has no identifier and its association, so that it cannot be compared to the type of type matching, as follows: struct {long a; double b;} a, & b = a, * c = & a; struct {long a; double b;} * d = & a; there is no problem with the above A, B, C, because the same type is used to define, even if this type is not identifically and it Mapping, but D will report an error, even if the definition of the back-written structure is the same as the exact same, but still not the same, just like it. What is the use? Next description. Finally, it should also be noted that when writing the previous declaration statement in the composite statement to define the structure, the previous variable scope is also applicable, that is, the structure defined in a composite statement, this composite statement, it is Delete, is equal to no definition. As follows: Void abc () {structure AB {long A, b;}; AB D; DB = 10;} void main () {{structure AB {long A, b, e;}; ab c; CE = 23; } AB A; // will report an error, saying AB is undefined, but there is no problem} Initialization initialization is the memory assignment assigned to the stack while defining the variable, such as: long a = 10; When the type of variable is defined, when a plurality of elements are represented, if the array type, the above structure type, multiple numbers need to be given.
In this regard, C gives a syntax, and uses a parent-bracket to enclose the value of the desire to assign the 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-mentioned syntax initialized for variables A, the braces enclose each element, and Use "," from ",". Note that ABC :: D is an array type, and the number of initialization used must also be enclosed with braces, so the above nested braces appear. It should now be understood that "{}" is only used to construct a number with multiple elements, so there can be a long A = {34}; and here "{}" is equal to not. It should also be noted that the number of numbers in C agreed to give the number of numbers in the corresponding custom type or array, namely: ABC A = {1, 2, 34}, b = {23, {34} , 65, {23, 43}}, c = {1, 2, {3, {4, 5, 6}}}; the above AD [0], AD [1], AD [2] is 0, Only BD [2] is 0, but C will report an error, because the nesting first braces also include {4, 5, 6}, indicating that the CC will be assigned by a number with two elements. However, the type of CC is float, with only one element, the compiler will say excessive initialization items. The previous A and B unfameted elements will be assigned 0, but should pay attention to 0 0, but simply fill the value of the unfameted memory, and then through the original code The format of the class is explained to 0 after the value is 0, which is not assigned 0 numbers. It should be noted that C agrees such grammar: long a [] = {34, 34, 23}; Here, the number of elements is not given when defined A, but is checked by the compiler to assign the number of parentheses for assigning the value, which determines the number of arrays, so the type of the above is long [3] . When a multidimensional array, such as: long a [3] [2] = {{1, 2}, {3, 4}, {5, 6}; Because each element is a number of multiple elements, it is the same as the previous ABC :: D. Recover the modified order of the type modifier, from left to right, but when repeating type modifier, you will fall from right to left, so it should be three long [2], not two long [ 3], thus this will be wrong: long a [3] [2] = {1, 2, 3}, {4, 5, 6}} ;. It should also be noted that C is more than just providing the initialization method of "{}" above, for strings, specifically provided by: char a [] = "abc"; The type of A here is CHAR [4] because the string "ABC" needs to accounted for 4 bytes of memory space. In addition to these two initialization methods, C also provides a functional initialization function, the next introduction. The type of use of CHAR A = -34; unsigned char b = (unsigned char) A; the above B is equal to 222, the -34 is written into a binary number 11011110 according to the complement format, and then this binary number is explained by the original code format, obtain value 222.
Continue: float a = 5.6f; Unsigned long b = (unsigned long) a; this back B is equal to 5. why? It should not be 5.6 in accordance with the format of IEEE's Real * 4 in the format of the binary 0x40b33333 (here the hexadecimal representation), and then this binary number is explained by the original code format to obtain a value 1085485875? Because type conversion is a semantic type conversion, not a type transformation. The two types can be converted, and the compiler is designed to define the conversion rules between these two types. For example, CHAR and UNSIGNED Char, the conversion is because the compiler defines the Char turn Unsigned Char, the same float turn Unsigned long is defined by the compiler as a finishing rather than round. Why have there be type conversion? has no meaning? Indeed, it is meaningless, it is meaningless, just to meet the rigorous syntax, but because C defines the conversion of the pointer type, and it is defined very well, so that it is very important. Char a = -34; unsigned char b = * (unsigned char *); the result of the above, the same, B is 222, but by converting char * into unsigned char *, then use unsigned char to come Interpret the corresponding memory to obtain 222, rather than converting according to the compiler, even if the result is the same. Therefore: float a = 5.6f; unsigned long b = * (unsigned long *) (& a); the above B is 1085485875, that is, the result of the previous thought. Here, the memory corresponding to the address is interpreted by the rules defined by the unsigned long, and the result is placed in B, which reflects how the type is how to explain the content in memory. The reason why it can be implemented is because C specifies the conversion between all pointer types. The numeric value has not changed, only type changes (but because the inheritance relationship of the class may change, the following description) The value is the result of the contents of the corresponding memory with unsigned long to explain the contents of the memory. Therefore, the previous article wrote four "==" when comparing OldLayout [Cursln] [0 ~ 3] and OldLayout [i] [0 ~ 3] to compare four char number, because the four char numbers are Continuously stored, so only the long digit can be saved as follows, saving excess three comparison time.
* (long *) & oldlayout [curd "== * (long *) & OldLayout [i] above is just an optimization means, for the semantics or not much, but because there is a custom type, Struct AB {long A1 Long A2;}; struct abc {char A, b; short c; long d;}; ab a = {53213, 32542}; abc * pa = (abc *) & a; 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 above execution, the values of AA, BB, CC, and DD are sequentially -35, -49, 0, 32542, and the values of AA1 and AA2 are 197121 and 4, respectively. I believe that as long as I think so, I should understand why A. A1 and A.A2 are not modified, and the results have changed because the variables are only a mapping, and the front is to interpret the pointer PA to interpret and operate A. The corresponding memory content. Therefore, using custom types and pointer conversions, you can realize what kind of rules look at the content of a block. What is the use? Passing a function of a function (using a pointer type or reference type), this function has another parameter, such as a long type. When the parameter of this long type is 1, it means that the pass is a set of orders; 2, indicating that the pass is a shipping order; 3 o'clock is a collection list. If you are equipped with the enumerated type below, you can write code with a very perfect semantic. It should be noted that since the pointer can be casually converted, there is a code that does not make sense, in this only understanding the 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 transfer is 0x1234 cd00 and 0x000000ab. Enumerates the above to explain 1 When the order is set, 2 is the shipping list and 3 when the payment will be used, and the Switch or IF statement can be used to determine, but the statement will see similar TYPE == 1 or TYPE = = 2 The class is unable to show semantics. C provides an enumeration type for this purpose. The format of the enumeration type and the previous custom type are very similar, but the meaning is completely different, as follows: enum ab {left, right = 2, Up = 4, down = 3}; ab a = left; switch (a) {casse Left :; // Doing the right thing with the left Case Up :; // Doing something with the corresponding thing} Enumerations should also be hosted with some identifiers with "{}", but these identifiers do not map the memory address. Map offset, but map integers, why is an integer, because there is no need to map floating point numbers, followed.
The above Right is equivalent to 2, pay attention to it is equivalent to 2, which is equivalent to a name, so it can be long b = left; double c = Up; char d = right; However, pay attention to the above variable A. Its type is AB, that is, an enumerated type, which is the interpretation rule is equivalent to int, which is compiled into a 16-bit operating system running, the length is 2 bytes, compiled into a 32-bit operation. There are 4 bytes on the system, but the int is a different type, and the previous assignment operation can be no problem, you can think that the compiler will implicate the enumeration type into an int type, there is no error above . However, you can't do it, because the type of variable A is ab, then its value must be one of the four identifiers listed above, and A = B; because B is long type, if it is 10, then One of the four identifiers in the above, so it is not possible. Note that the above LEFT does not write "=", and will increase from the value of one identifier in front of it, because it is the first, and C is specified as 0, so the value of Left is 0. It should also be noted that the numbers of the above maps can be repeated, ie: enum ab {left, right, up = 5, down, top = 5, Bottom}; the above identifier sequentially mapped to 0, 1, 5, 6, 5,6. Therefore, the problem that is the most beginning to handle: Enum operationType {ORDER = 1, invoice, checkout}; and the type of the parameter can be OperationType, so the semantics are far beyond the original code, readable It is much higher. Therefore, when the concept of some human world is mapped into a number, they found that their differences are not expressed on numbers, such as eating, sleeping, playing represents a state of a person, now in order to map people's concepts, it is also necessary to Status This concept is mapped into numbers, but it is clearly a convenient mapping rule. At this time, I forced 1 means to eat, 2 represents sleep, 3 represents playing, at this time, you can define 1, 2, 3 into an enumeration to express semantics, this is why enumeration is only defined as an integer, because no definition The necessity of floating point numbers. As mentioned earlier, you can connect Struct, Class, and Union, which can be connected to Struct, Class, and Union. When UNION is connected, it is a combined custom type (simply as union). Its and struct's difference is that the latter is a serial distribution to define member variables. And the former is a parallel distribution. As follows: Union ab {long A1, A2, A3; FLOAT B1, B2, B3;}; AB A; Variable A length is 4 bytes, not 6 * 4 = 24 bytes, while combined with AB The offset of the six variable mappings defined in it is 0. Therefore, A.a1 = 10; after execution, the value of A.A1, A. A. A. A. A. A1, A. A. A. B1 is much, and the value of the IEEE's Real * 4 is used to explain the contents of the corresponding memory. How much is it.
That is, the first use of the pointer to explain the contents of different memory, and now you can complete it, so the above code is moved to: union ab {struct {long a1; long A2;}; structure { CHAR A, B; SHORT C; Long D;};}; AB A = {53213, 32542}; char AA = AA, BB = AB, CC = AA, LONG DD = Ad; AA = 1; AB = 2; AC = 3; AD = 4; long aa1 = a.a1, aa2 = a.a2; result is constant, but the code is simple, only defined a custom type, and there is no pointer variable, the semantic change of the code It is much more obvious. Note that two structures are defined in it again when defined in combination AB, but there is no name word, which is a special usage of C . When using the type definition in the middle of the type definition, if the type binding identifier defined by the type definition is not defined, the variable of the offset type is still defined, but these variables become a member variable of the upper custom type. Therefore, "{}" is equal to no, the only meaning is to indicate the distribution of variables through the front Struct or Class or Union. It can therefore be as follows: struct ab {structure {long A1, A2;}; CHAR A, B; Union {float b1; double b2; structure {long b3; float b4; char b5;};}; short c;}; The member variable of the custom type AB has a1, A2, A, B, B1, B2, B3, B4, B5, C. The respective offset values are 0, 4, 8, 9, 10, 10, 10, 14, 18, 19, the total length of type AB is 21 bytes. A type of length indicates that if a variable is defined with this type, the compiler should assign how much continuous space on the stack, C provides an operator SIZEOF for this purpose, and the right side of the right side or the type name, when the number When it returns the size of the memory space, when the type of memory is required, the type name is returned to the type of memory space that needs to be occupied by the type name. So long a = sizeof (ab); AB D; long b = sizeOf d; After execution, the values of A and B are 40. How is 40? Shouldn't it be 21? The offset corresponding to the previous member variables is also actually 0, 4, 8, 9, 16, 16, 16, 20, 24, 32. why? This is the so-called data alignment. The CPU has certain instructions that need to process multiple data, and the interval between each data must be 4 bytes or 8 bytes or 16 bytes (varying intervals varying different instructions), which is called data alignment. When the interval between each data does not meet the requirements, the CPU must do additional work to align data, and the efficiency will drop. And the CPU does not directly read things from memory, and the CPU buffer (one access speed built by the CPU is faster than the memory hardware), and the size of this buffer is definitely 2, but It is relatively small, so the size of the custom type is preferably two times in two times to use high-speed buffering.