C ++ from scratch (four) - assignment operator

xiaoxiao2021-03-06  54

C starts from scratch (four)

- Assignment operator

This article is "C continues from zero (2)", indicating that "C from scratch (2)" has left the expression of the expression, and make a little pavement for the application of the next pointer. Although the above has explained what variables are, the most critical thing for variables is not explained due to space limitations, the following will explain how to access memory.

Assigning statement

As mentioned earlier, to access the memory, you need the corresponding address to indicate which number of memory, and the variable is a mapping, so the variable name is equivalent to an address. For memory operations, in general, only the values ​​in the memory and write the numerical write memory (no assignment and release of memory), in C , in order to write a value corresponding to the address corresponding to a variable In the memory (for easy, the address corresponding to the corresponding variable A is the address of the variable A, and the memory identified by the address of the direct variable A) is a variable A), only the number of variable names, then "=", then Digital (for numbers, please refer to "C from zero (2)") and semicolons. As follows: A = 10.0F; B = 34; Because the number is received, it can be connected and the code required to calculate the corresponding expression is generated by the compiler, and can be as follows: c = a / b * 120.4f The upper sentence, the compiler will generate the CPU instruction for division and multiplication, after calculation (that is, after the value of expression A / b * 120.4f), it will also generate the calculation result to the variable at the same time. C The CPU command to the CPU is the basic role of the statement (for the statement, "C will be described in detail in the zero (six)"). When writing assignment statements, you should make sure that this statement has been defined before, so that the compiler can find the address of the corresponding variable while generating the CPU instruction to assign assignments, and then complete the generation of the CPU instruction. As mentioned above, A and B, you need to write the following variable definition before writing the above statement: float a; long b; direct writing variable name is also a statement, which causes the compiler to generate a statement to read the content of the corresponding variable. . It can be written as follows: a; the above will generate a statement read memory, even if the number read from the memory does not apply any applications (of course, if the compiler has an optimized option, the above statement will not generate any code) . From this point and the C = A / B * 120.4F; the statement, it can be seen that the variable can return numbers. The number returned by the variable is the number of content obtained in the variable corresponding memory according to the type of variable. This sentence may not be so easy to understand, it should be understood after reading the type of time after reading the section. Therefore, in order to write data to a piece of memory, use the assignment statement (ie, equal sign); to read a piece of memory, writing the variable name identifies the memory. So you can write: a = a 3; assuming that A original value is 1, then the above assignment statement takes the value of A, plus 3, resulting in results 4, and write 4 to A. Since C uses "=" to represent assignment statements, it is easy to confuse the equivalent in math, which should be noted. And the above float A; statement, when there is no assignment operation of the variable, what is the value of A? God knows. What is the content of A at the time (for the VC compiler, when the debug option is turned on, use 0xcccccccc to populate these uninterected memory), use the IEEE's Real * 4 format to explain it and get a corresponding number, also It is the value of A.

Therefore, it should be assigned when the variable is defined (but there will be performance impact, but small) to prevent inexplicable values ​​in initialization variables, such as: float a = 0.0f ;. Assignment operator

The above A = A 3; meaning is to increase the value of A. In C , a self-written scheme is given to this situation, that is, the previous statement can be written: A = 3; It should be noted that the two statements are logically intended to increase the value of the variable A, but they actually distinguish, the latter can be compiled into optimized code, because it means that the value of a piece of memory is increased The quantity, and the former is written to a block in a block. So if possible, try to use the latter, namely A = 3; This statement allows the compiler to optimize (but because the current compilers are very intelligent, A = A 3 can be found; it is the value-added operation of a memory rather than a memory assignment, so two statements above In fact, it can be considered exactly the same, only with a short written function). For the above situation, it is also possible to apply binary non-logical operators such as subtraction, multiplication, that is, not a logic value operator, that is, A && = 3;), such as: a * = 3; A - = 4; A | = 34; A >> = 3; In addition to the above shorthand, C also provides a story, namely A ;, it is logically equivalent to A = 1; Also, in computer programming, add one and reduced one is often used, so the CPU specializes in two instructions to perform plus one and minus actions (transfer to assembly language is INC and DEC), but the speed is directly passed The addition or subtraction instruction is required to perform much. For this purpose, " " and "-" operators are also provided to correspond to INC and DEC. So A ; although logically and A = A 1; equivalent, it is actually different due to the optimization process of the compiler, but is therefore, because the compiler is intelligent, it is possible to see A = A 1; can be compiled into an INC directive, even if A is not used; but still can be optimized, so A ; will only have a short written meaning. It should be aware that A = 3; this statement will also return a number, that is, the value of the value A after A is assigned. Since it can return numbers, "=" is the operator according to "C ", "=" belongs to the operator, and it can be written as follows: c = 4 (a = 3); the reason why parenthesis is because The priority of "=" is lower than " ", and more common and normal applications are: c = a = 3; it should be noted that the C and A are assigned to 3, but in A is assigned by 3 Assign a value to C, although the last results and C, A are assigned to be 3, but should not be understood. Due to A ; it is representing A = 1; it is a = A 1; and therefore A ; will also return a number. Also because of this reason, C provides another shorthand, A ;. Assuming A is 1, then A ; the value of A will be returned, 1, and then add a value of A; A; first add A to one, return A, 2. This is also the same, but it is just a reduction.

The above variable A is defined by the top variable, which is the variable of the float type, which uses the operator and cannot be optimized because the float type is a floating point type, which is used to use the IEEE's Real * 4 format. Digital, not binary or complement, and the incompativation of the INC and DEC instructions are out of the binary representation, so if the floating point type variable is used " "The operator will be completely just short-handed, without any optimization effect (of course, if the CPU provides a new instruction set, such as MMX, etc., to make a quick and unhading of the REAL * 4 format, and the compiler supports the corresponding The instruction set is still possible to generate an optimized effect). Return value for assigning operators

Before you learn the difference between A and A , you will first understand the calculation of the operator (Evaluate). The operator is to do some of the given numbers and return a number. The calculation of the operator is to perform the processing of the operator, and return a value. Asneated, the operator can be a symbol, and the number can be connected to both sides, that is, other operators, but also because the assignment operator belongs to an operator, so the execution order of the operator becomes quite important. For A B C, A B will be executed, and the operation (A B) C will be executed. You may feel that there is nothing, then as follows, suppose 1: c = (a * = 2) (A = 3) before A 5. C = (a = 3) (a * = 2); after execution, A is 8. So what C? The result may be great to be unexpected. The former C is 10, and the latter C is 16. The above is actually a barrier method, with " " there is no meaning, that is, the reason why it will be implemented from left to right is not because " ", but because (a * = 2) and (a = 3) The priority is the same, and according to "()", it is calculated from left to right. But why is C's value not expected 2 5 and 4 8? Because the relationship between the return value of the assignment operator. The number returned by the assignment operator is not the value of the variable, but the address corresponding to the variable. This is very important. As mentioned earlier, the object writes a variable name will return the value of the corresponding variable, that is because the variable is a mapping, the variable name is equivalent to an address. The numbers as a very special operator in C , that is, any one of the characters. And the address is the same as the long integer, single-precision floating point, is a type of number. When a number is the address type, as an operator, it does not have the number to operate, only the contents of the memory identified by this number as the address (interpretation of this address). The address can be obtained by a variety of ways, and if the above optical write a variable name, the corresponding address can be obtained, and the type of address obtained is the type of corresponding variable. If this sentence can't be understood, you should understand after reading the following types. So the previous C = (A = 3) (a * = 2); because "()" participates in the participation, two assignment operators are performed first, and then two assignment operators return A. The address, then calculate the value of " ", calculate the address of both sides (A address is also an operator), that is, the value of the A-two assignment operation has been executed, 8, the last C is 16. The other is also 10 due to the same reason. Now consider the calculation order of the operator. Different operators have different calculation sequences when several priority operators appear at the same time. The previous "()" and "*" and other computational order are calculated from left to right, and "!", Negative "-", etc. They are all calculated from right to left, such as! - !! a ;,

First calculate the value of the third "!"! "!" From the left chart, resulting in the value of the address of the calculation A, 3; then logic to be counter-0, then calculate the second "!" Value, logic retrofit Get 1, then calculate the value of the negative "-", obtain -1, finally calculate the first "!" Value, get 0. The assignment operator is calculated from right to left, except for the suffix " " and suffix "-" (ie, A and A-A-). Therefore, C = a = 3; C = (a = 3) is then calculated, and 3 is written to C. Instead of calculating C = A, then calculating C = A, returning C = a, then calculating the second "=", writing 3 to C, which is not assigned and there is a problem. Also: a = 1; c = 2; c * = a = 4; due to the same priority of "* =" and " =", calculate A = 4 from right to left, to get A is 5, Then return A's address, then calculate the value of the address A of A, calculate "* =" so that the value of C is 10. Therefore, according to the previous, A will return A's address, and A must return an address because it is assigning operator, but it is clear that the address of A will be written, so the compiler will write code in the stack. Assign a piece of memory in the same size, and copy a value to this temporary memory, then return the address of this temporary memory. Since this temporary memory is allocated because of the needs of the compiler, it does not matter to the programmer, so the programmer should not write this temporary memory (because the compiler is responsible for compiling the code. If the programmer wants to access this Block memory, compiler will be an error), but you can read its value, which is the main purpose of the return address. So the following statement is not problematic: ( a) = a = 34; but (A ) = a = 34; will be in compile time, because the memory identified by the address returned by the A can only be responsible by the compiler Processing, programmers can only get their value. The meaning of A is the value of A, that is, the address of the temporary memory mentioned above, and then adds the value of the variable one. If multiple A appears at the same time, each A needs to assign a temporary memory (note the previous C = (a = 3) (a * = 2); the description will be a bit bad, and A means means First return A's value, then when is the value of A? In the VC, when the suffix " " or suffix "-" appears in the expression, only one temporary memory is allocated, and then all the suffix " " or suffix "-" return this temporary memory address, then After all the values ​​of other operators that can be calculated, the value of the corresponding variable is written to the temporary memory, calculate the value of the expression, and finally add the value of the corresponding variable or minus one.

Therefore: A = 1; C = (A ) (A ); after execution, the value of C is 2, and the value of A is 3. And as follows: a = 1; b = 1; c = ( a) (a ) (b * = 2) (a * = a ); execution, allocate temporary Memory, then due to 5 "()", the calculation order is from left to right, calculates a value, returns the address of the added A, a value of 2 calculates the value of A , returns temporary memory Address, the value of A is still 2 calculation of A in B * = A , returns the address of the temporary memory, and the value of A is still 2 calculation of "* =" in b * = a , writing A value to temporary memory, The value of the calculated B is 2, the address of the return B is calculated, and the value of A * = 2 is returned. The value of A is 4 calculated A * = A , and the address of the temporary memory is still. 4 Calculate "* =" in A * = A , write A value to temporary memory, return A's address, and a value of 16 calculates the remaining " ", to perform the value of A Temporary memory, the value of 16 16 2 16 16 is 66, and the three A owes the addition of three A in writing, and the last changes to 19. The above is so much, not just want to warn you - using assignment operators in the expression is not respected. Because it does not meet the habits of normal mathematical expressions, and the order of calculation is easy to mix. If there are multiple " " operators, it is best to separate the expression, otherwise it is easy to cause errors to calculate errors. And leading to the order of calculation or more than the above A , in order to let you pay more attention to the red word in front, the following will introduce more fireful things, if you have agreed to the red word above, then the section can be completely Skip, it can think that there is no meaning for programming (if you don't know its existence). Sequence Point and Additional Effects (Side Effect)

When C = A is calculated, the value of A is also increased when the value of C is calculated, and the value of A is added to the additional effect of the previous expression. What is the problem? It may affect the calculation results of the expression. For a = 0; b = 1; (a * = 2) && (B = 2); because two "()" priority is the same, "* =" is calculated from left to right, calculate "* =" and return A Address, then calculate " =" and return B's address, and finally the logic fake is returned due to a value of A. Very normal, but the efficiency is low. If the numbers on the left of "&&" are already 0, they no longer need to calculate the ones of the right. Similarly, if the numbers on the left of "||" are not zero, no need to calculate the number of the right side. Because "&&" and "||" are mathematically, the mathematics does not care about the value on the left side or the value on the right, so the results will not change, so "&&" and "||" will do it just now Explanation. This is also C guaranteed, which not only meets the definition of mathematics, and provides an optimized approach ("&&" and "||" on the right side of the right do not have to be calculated). Therefore, the above form is explained - if a is 0 after the self-line 2, then b does not have to increase 2. This obviously violates our original intention, think that B will be self-increasing 2 anyway. However, C guarantees such that not only because of mathematical definition, it is also optimized due to code generation. However, according to the priority of the operator, the above B = 2 is still executed (this is why we will write the above code). In order to achieve a 0 when A is 0, B = 2 will not be calculated, C presents the concept of a sequence point. The sequence point is some special positions, and the C is forcibly defined (C does not give the definition of the sequence point, so different compilers may give different sequence points definitions, and VC is a sequence point defined according to the C language). When the operator is calculated, if a sequence point is encountered, the value at the sequence point must be prioritized to ensure some special purposes, as the above guarantee is not calculated when A is 0, and the sequence is Point-related operators (as "&&" and "||") will also be calculated before returning to normal calculations. The calculation of the leftmost number of "&&" is a sequence point, and the calculation of the left number of "||" is also. C defines a plurality of sequence points, including the expression calculation under conditions such as conditional statements, function parameters, etc., without specific understanding of what sequence points, only need to know the calculation of the assignment operator due to the presence of the sequence point I unexpected. Next, an example: a = 0; b = 1; (a * = 2) && (B = a); according to the priority order, the compiler finds to calculate a * = 2, then calculate A, then " =", finally calculate "&&". Then the compiler discovers this calculation process, and the number of the number of "&&" appears in the "&&", which is guaranteed to be prioritized, so it may not be used to calculate B = A.

Therefore, the compiler first calculates "&&" numbers. By the above calculation process, the compiler is found to calculate the number of "&&" on the left of the "&&", so the address, returning A, returns A, returns A, returns A, Then calculate the numbers on the left of "&&", the value of A is 0, so it does not calculate B = A. Instead, because the relationship between the priority is first, the A is added to the calculation to return to 1. Therefore, after the calculation is calculated, A is 0, B is 1, return 0, indicates logic fake. Therefore, the appearance of the sequence point is to ensure some special rules, as "&&" and "||" above. Consider "," operator, its operation is calculated on both sides, then returns the number of the right, namely: A, B 3 will return B 3 value, but a is still calculated. Because "," is the lowest (but higher than the "digital" operator mentioned above, if A = 3, 4;, then A will be 3 instead of 4, because first calculate "=", Returns the address of A and then calculates ",". Also: a = 1; b = 0; b = (a = 2) ((a * = 2, b = a - 1) && (c = a)); due to "&&" left figures are a sequence point Therefore, the value of A * = 2, B is calculated, but according to the return value of "," only returns the number of the right, so it does not calculate the A * = 2 and directly calculate B = a - 1 to 0, "&& "It is returned, but A * = 2 is not calculated and the value of A is still 1, which violates", "definition. In order to eliminate this (of course, there may be other applications ",", ",", ",", "," the left number is set to the sequence point, that is, it will be prioritized "," the number on the left to ensure "," definition - Calculate the numbers on both sides. Therefore, the above due to ",", ",", ",", ",", ",",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, Restore normal priority, and calculate c = a, 2, and finally restore normal priority order, execute A = 2 and " ". As a result, A is 4, C is 2, B is 5. So the previous A = 3, 4; actually, the compiler first discovered "," this sequence point, and found that "," the value of the left, must first calculate a = 3, so calculate A = 3 first So that the sensory sequence point does not seem to have a role. The following formula Please analyze it. After execution, A is 4, but if "", "is changed to" && ", A is 2. A = 1; b = (a * = 2) (A * = 3), (a - = 2)); if you are very halo, it doesn't matter, because the above content can be considered meaningless, Writing here is just to further prove to you, using the assignment operator in the expression, even if it may let you write a concise statement, but it also reduces the maintenanceability of the code. Type conversion

Said in "C from scratch (2)", the number can be a floating point number or an integer or other, that is, the number is type. Note "C is explained in the type of type from scratch (3)". The type is only explained how to explain the state, and it has already been said in the foregoing, for convenience, use the binary number to represent the state, so that the type can be used to tell the compilation How to explain the number of binary numbers. Therefore, a long integer number is to tell the compiler to explain the status of the obtained binary number in accordance with the format of binary complement to obtain a value, and a single-precision floating point number is to tell the compiler The status of the binary number indicated by the compiler Interpretation is explained in the format of IEEE's Real * 4 to obtain a value of a decimal. Obviously, the same binary number is expressed, the interpretation will be interpreted in different types, and how do the compiler know what type should be used to explain the binary number? As mentioned earlier, the number is a very special operator, which has no operand, only returns a state indicated by the binary number of its type (in order to facilitate, "said" binary representation " number"). The operator is to execute the instruction and return numbers, so all operators to last execution is returning a binary number. This is important, there is an important meaning for the understanding of the later pointers. See 15 first; this is a statement because 15 is a number. Therefore, 15 is considered a number of char types (because it is less than 128, there is no representation range of char), and a 8-bit long binary number will be returned, and this binary number is written according to the completion format, and 00001111. Look at 15.0f, I: Although the value of the above 15 and 15.0f is equal, since different types result in different formats, even the length of the binary number is used is different. So if you write 15.0F == 15; 0 will return 0, indicate logic fake. But actually returns 1, why? Since the above 15 and 15.0f are expressed as completely different two binary numbers, we think that 15 and 15.0f are equal, but their binary representation is different. What should I do? The 15 value is explained in the REAL * 4 format of the 15.0F of the IEEE, and then writes the binary number in 8-bit binary complement format, and then compares the binary number of the original representation 15. In order to achieve the above operation, C provides type conversion operators - "()". It looks like a bracket operator, but the format is different: () or (). The of the above type conversion operator is not a number, so it will not be operated, but as a parameter to control how it is operated . is an identifier that uniquely identifies a type, such as Char, Float, etc. The return value of the type conversion operator is as indicated by its name, and the is explained in the type of ID, the return type is the number of . Therefore, the above example needs to be written as follows: 15 == (char) 15.0f; now it can return 1, indicating that the logic is really.

But even if you do not write (char), the previous statement is returned to 1. This is a compiler for convenience and helping us add (float) before 15, so still returns 1. This is called implicit type conversion, and it will also be mentioned when the class will be explained later. When a type can replace another type, the compiler will perform the above implicit type conversion and automatically add the type conversion operator. Such as: char can only represent an integer of -128 to 127, while Float can significantly represent these numbers, so the compiler performs implicit type conversion. It should be noted that this implicit conversion is requested by the operator, ie the previous "==" requires the same number type on both sides. It is found that the two sides are different, and the result compiler converts char to FLOAT, then execute "==" operating. Note: In this case, the compiler always converts a poor type (such as the previous char) to a better type (such as the previous FLOAT) to ensure that the numerical truncation problem does not occur. Such as: -41 == 3543; On the left is char, the right side is Short, because Short is better than Char (Short can completely replace char), so actually: (Short) -41 == 3543;, return 0 . And if it is -41 == (char) 3543; because the char can not represent 3543, 3543 is transferred to a binary number 0000110111010111, then take it low, resulting in a high 8-bit 00001101, this is called It is truncated. Results (CHAR) 3543 The return value of CHAR is a binary number 11010111, which is -41. Results -41 == (char) 3543; the return value will be 1, indicating that the logic is really wrong. So the previous 15 == 15.0f; the actual (float) 15 == 15.0f; (Note that the 15 compiler is explained as a CHAR type is not accurate, more compiler is explained to int type) . Note that the previous direction is moving well (ie char to float), it is entirely because of "==", it requires this. The following is "=": short b = 3543; char a = b ;. Since the value of B is a short type, and the requirements of "=" are necessary to turn the number on the right side of "=" to the left, so that the correct memory is written (simply returning the number of binary numbers on the right) In the memory represented by the address on the left). Therefore A will be -41. However, the compiler is implicitly converted according to the requirements of "=", which may be due to the negligence of the programmer without discovering this error (as the value of B must be within -128 to 127), so the compiler will A warning is given to the above situation, saying that the value of B may be truncated. In order to eliminate the doubts of the compiler, as follows: CHAR A = (char) b ;. As is called the display type conversion, it tells the compiler - "I know that the data may be truncated, but I don't have truncated". Therefore, the compiler will no longer issue a warning. The following: CHAR A = (char) 3543; Since the compiler can affirm that 3543 will definitely be truncated, the error returned value, so the compiler will give a warning, indicating that 3543 will be truncated, regardless of the previous type conversion operation Whether it exists.

转载请注明原文地址:https://www.9cbs.com/read-115421.html

New Post(0)