|
|
HP C/HP-UX Reference Manual: Version A.05.55.02 > Chapter 5 Expressions
and Operators Assignment Operators (=, +=, -=, *=, /=, %=,<<=, >>=, &=, ^=, |=) |
|
The assignment operators assign new values to variables. The equal sign (=) is the fundamental assignment operator in C. The other assignment operators provide shorthand ways to represent common variable assignments. When the compiler encounters an equal sign, it processes the statement on the right side of the sign and assigns the result to the variable on the left side. For example: x = 3; /* assigns the value 3 to variable x */ An assignment expression itself has a value, which is the same value that is assigned to the left operand. The assignment operator has right-to-left associativity, so the expression a = b = c = d = 1; is interpreted as (a = (b = (c = (d = 1)))); First 1 is assigned to d, then d is assigned to c, then c is assigned to b, and finally, b is assigned to a. The value of the entire expression is 1. This is a convenient syntax for assigning the same value to more than one variable. However, each assignment may cause quiet conversions, so that int j; assigns the truncated value 3 to both f and j. Conversely, j = f = 3.5; assigns 3.5 to f and 3 to j. C's assignment operators provide a handy way to avoid some keystrokes. Any statement in which the left side of the equation is repeated on the right is a candidate for an assignment operator. If you have a statement like this: i = i + 10; you can use the assignment operator format to shorten the statement to i += 10; In other words, any statement of the form var = var op exp; /* traditional form */ can be represented in the following shorthand form: var op = exp; /* shorthand form */ where var is a variable, op is a binary operator, and exp is an expression. The only internal difference between the two forms is that var is evaluated only once in the shorthand form. Most of the time this is not important; however, it is important when the left operand has side effects, as in the following example: int *ip; The second statement is ambiguous because C does not specify which assignment operand is evaluated first. See “Operator Precedence ” for more information concerning order of evaluation. Whenever you assign a value to a variable, the value is converted to the variable's data type if possible. In the example below, for instance, the floating-point constant 3.5 is converted to an int so that i gets the integer value 3. int i; Unlike arithmetic conversions, which always expand the expression, assignment conversions can truncate the expression and therefore affect its value. For example, suppose c is a char, and you make the following assignment: c = 882; The binary representation of 882 is 00000011 01110010 This number requires two bytes of storage, but the variable c has only one byte allocated for it, so the two upper bits don't get assigned to c. This is known as overflow, and the result is not defined by the ANSI/ISO C standard or the K&R language definition for signed types. HP C simply ignores the extra byte, so c would be assigned the rightmost byte: 01110010 This would erroneously give c the value of 114. The principle illustrated for chars also applies to shorts, ints, and long ints. For unsigned types, however, C has well-defined rules for dealing with overflow conditions. When an integer value x is converted to a smaller unsigned integer type, the result is the non-negative remainder of x / (U_MAX+1) where U_MAX is the largest number that can be represented in the shorter unsigned type. For example, if j is an unsigned short, which is two bytes, then the assignment j = 71124; assigns to j the remainder of 71124 / (65535+1) The remainder is 5588. For non-negative numbers, and for negative numbers represented in two's complement notation, this is the same result that you would obtain by ignoring the extra bytes. You may assign an integer value to a floating-point variable. In this case, the integer value is implicitly converted to a floating-point type. If the floating-point type is capable of representing the integer, there is no change in value. If f is a double, the assignment f = 10; is executed as if it had been written f = 10.0; This conversion is invisible. There are cases, however, where a floating-point type is not capable of exactly representing all integer values. Even though the range of floating-point values is generally greater than the range of integer values, the precision may not be as good for large numbers. In these instances, conversion of an integer to a floating-point value may result in a loss of precision. Consider the following example: #include <stdio.h> If you compile and execute this program, you get: j is 2147483600 The most risky mixture of integer and floating-point values is the case where a floating-point value is assigned to an integer variable. First, the fractional part is discarded. Then, if the resulting integer can fit in the integer variable, the assignment is made. In the following statement, assuming j is an int, the double value 2.5 is converted to the int value 2 before it is assigned. j = 2.5; This causes a loss of precision which could have a dramatic impact on your program. The same truncation process occurs for negative values. After the assignment j = -5.8; the value of j is -5. An equally serious situation occurs when the floating-point value cannot fit into an integer. For example: j = 999999999999.0 This causes an overflow condition which will produce unpredictable results. As a general rule, it is a good idea to keep floating-point and integer values separate unless you have a good reason for mixing them. As is the case with assigning floating-point values to integer variables, there are also potential problems when assigning double values to float variables. There are two potential problems: loss of precision and an overflow condition. In HP C a double can represent approximately 16 decimal places, and a float can only represent 7 decimal places. If f is a float variable, and you make the assignment f = 1.0123456789 the computer rounds the double constant value before assigning it to f. The value actually assigned to f, therefore, will be 1.012346 (in double-to-float conversions, HP C always rounds to the nearest float value). The following example shows rounding due to conversions. /* Program name is "float_rounding". It shows how double values The output is Value of f64: 7.4844709 A serious problem occurs when the value being assigned is too large to be represented in the variable. For example, the largest positive number that can be represented by a float is approximately 3e38. However, neither the K&R language definition nor the ANSI/ISO C standard defines what happens if you try to make an assignment outside this range. Suppose, for example, that your program contains the following assignment: f = 2e40; In this simple case, the compiler recognizes the problem and reports a compile-time error. In other instances, however, a run-time error could result. /* Following are examples of the use of each |
|