More on Expressions
Expressions do most of the work of a C program. Expressions handle
arithmetic operations as well as other things like calling functions.
Operators
Operators are the connections between elements of an expression, for
instance, + for addition. As in algebra, every operator has
a precedence, a priority among the other operators as to
which gets evaluated first. For example, in the expression
a + b * c, the multiplication of b and c
comes first even though a comes first from left to right
because multiplication has a higher precedence than addition.
Precedence can be overridden, again as in algebra, with parentheses,
e.g. (a + b) * c.
In addition to precedence, there is also another property of operators:
their associativity. Some operators associate from left to
right, for example, the following divisions: a / b / c are
performed like this:(a / b) / c. Other operators associate
from right to left. For some operators like +, it doesn't
really matter since addition has the associative property, i.e.,
(a + b) + c is the same as a + (b + c).
Here is a list of C operators, in order from highest to lowest
precedence, giving their associativities. Some operators seem to be
listed more than once, like -; these are instances where the
same symbol is used to represent two different operators, like unary
minus (the minus sign) and binary minus (subtraction). Many of these
operators have special purposes beyond the scope of this lecture;
we will go into these in more detail later.
1 () [] -> . lr
2 ! ~ ++ -- + - * & (type) sizeof rl
3 * / % lr
4 + - lr
5 << >> lr
6 < <= > >= lr
7 == != lr
8 & lr
9 ^ lr
10 | lr
11 && lr
12 || lr
13 ?: rl
14 = += -= *= /= %= &= ^= |= <<= >>= rl
15 , lr
Integer, Floating Point, and Mixed Arithmetic
When all of the objects involved in an expression are integers, the
resulting values are also integers. For instance, consider the
following program:
#include <stdio.h>
int main () {
int a;
a = 2 * (100 / 5);
}
The computation involves only integer constants and variables, so
all the arithmetic is integer arithmetic. This is usually what we want,
but there are some cases when this can lead to confusion:
- Integer division results in an integer. In C, 21 / 5 is
4, not 4.20 or 4 and 1/5. You can find the remainder with the modulus
operator, %. For example, 21 / 5 is 4 remainder 1, so 21 % 5 is 1.
- C integers have limits on the numbers they can hold. This is normally
not a problem, but when working with large integers, intermediate results
represented as integers can overflow the number of bits needed.
For example, consider the following C program:
#include <stdio.h>
int main () {
int a, b, c;
a = 1000000;
b = 1000000;
c = (a * b) / 1000000;
printf ("%d\n", c);
}
The output is clearly supposed to be 1,000,000, but when I run it on my
computer I get -727. Although 1,000,000 is well within the 32-bit limit
of my computer, the intermediate result the computer gets when multiplying
1,000,000 by 1,000,000 overflows 32 bits and the result is garbage.
Floating Point Arithmetic
floats and doubles overflow less frequently because they
can represent much larger numbers at the expense of precision. All floating
point arithmetic in C is done in the double format; if a float
is involved in an expression, its value is converted to double
before it is used. If an assignment to a float is being made,
the result is automatically changed from double to float
at the end of the execution of the expression. It is important when working
with floating point arithmetic that you specify constants as floating point
even when they are integers, e.g., 5.0 instead of just 5. This makes it
clear to both the reader and the compiler that the math is being done in
a floating point context.
Mixed Arithmetic
When an expression involving both integer and floating point objects
is evaluated, the integer values are changed into doubles right
before they are used in a floating point operation. So in the expression
(30 / 20) + (10.0 / 20)
the 30 / 20 part is done as integer arithmetic, so that result is 1 (remainder
10). Since the second division involves a floating point constant 10.0,
the integer constant 20 is changed to double and then the division
is peformed in floating point, yielding 0.5. So the entire sum is 1 + 0.5
= 1.5.
Errors in Arithmetic
There are several kinds of errors one can make when writing a program
with arithmetic expressions. Some of them are caught during compile-time,
for example, trying to put a floating point value into an integer.
Others can only be found at run-time, like division by zero, taking
the square root or logarithm of a negative number, or evaluating the
tangent function at its asymptotes. C is special in that some arithmetic
errors can occur without generating any error messages at all, like
overflowing integer arithmetic.