HPlogo HP C/HP-UX Reference Manual: Version A.05.55.02 > Chapter 5 Expressions and Operators

Assignment Operators (=, +=, -=, *=, /=, %=,<<=, >>=, &=, ^=, |=)

» 

Technical documentation

Complete book in PDF

 » Table of Contents

 » Index

Syntax

lvalue = expression

Simple assignment.

lvalue += expression

Addition and assignment.

lvalue -= expression

Subtraction and assignment.

lvalue *= expression

Multiplication and assignment.

lvalue /= expression

Division and assignment.

lvalue %= expression

Modulo division and assignment.

lvalue <<= expression

Left shift and assignment.

lvalue >>= expression

Right shift and assignment.

lvalue &= expression

Bitwise AND and assignment.

lvalue ^= expression

Bitwise XOR and assignment.

lvalue |= expression

Bitwise OR and assignment.

Arguments

lvalue

Any expression that refers to a region of storage that can be manipulated.

expression

Any legal expression.

Description

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.

The Assignment Operator (=)

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 */
x = y; /* assigns the value of y to x */
x = (y*z); /* performs the multiplication and
assigns the result to 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;
double f;
f = j = 3.5;

assigns the truncated value 3 to both f and j. Conversely,

j = f = 3.5;

assigns 3.5 to f and 3 to j.

The Other Assignment Operators

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;
*ip++ += 1; /* These two statements produce */
*ip++ = *ip++ + 1; /* different results. */

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.

Assignment Type Conversions

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;
i = 3.5;

Integer to Character Conversions

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.

Integer to Float Conversions

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>
int main(void)
{
long int j = 2147483600;
float x;
x = j;
printf("j is %d\nx is %10f\n", j, x);
exit(0);
}

If you compile and execute this program, you get:

j is 2147483600
x is 2147483648.000000

Float to Integer Conversions

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.

Double to Float Conversions

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
can be rounded when they are assigned to a float. */
#include <stdio.h>
int main(void)
{
float f32;
double f64;
int i;
for (i = 1, f64 = 0; i < 1000; ++i)
f64 += 1.0/i;
f32 = f64;
printf("Value of f64: %1.7f\n", f64);
printf("Value of f32: %1.7f\n", f32);
}

The output is

Value of f64: 7.4844709
Value of f32: 7.4844708

Floating-Point Overflows

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.

Example

/* Following are examples of the use of each
* assignment operator. In each case, x = 5
* and y = 2 before the statement is executed. */

x = y; x = 2
x += y + 1; x = 8
x -= y * 3; x = -1
x *= y + 1; x = 15
x /= y; x = 2
x %= y; x = 1
x <<= y; x = 20
x >>= y; x = 1
x &= y; x = 0
x ^= y; x = 7
x |= y; x = 7
x = y = 1 x = 1, y = 1

© Hewlett-Packard Development Company, L.P.