Next: Simple Input/Output Up: The C Language Previous: The Second C Program

Operators, Precedence and Associativity

We have used a few relational operators, such as < or >, in our examples so far. These are members of a set of relational operators that can be used in C programs which are summarised in table 2.2


Table 2.2: Relational Operators in C
C notation for operator Relation
< less than
> greater than
<= less than or equal
>= greater than or equal
== equal
!= not equal

The use of the ! character to indicate the negation of a relation is general in C, but it is important to note that ! is a unary operator (operates on a single entity) in all cases. In some circumstances, the arithmetic minus sign, -, acts as a unary operator, as in the expression exp(-1.3), but the interpretation of - depends on the context. In the expression exp(x - y), it is clear that the - acts as a binary operator (note that there is no unary + in C). The case of the binary operator != uses this sense of negation, but specific to the test for inequality. Thus it would not be correct to use a binary operator in the form !> to mean not greater than, but of course, the <= operator does mean not greater than. It is important to note that the equal to relational operator is the 2-character string ``=='' and not the single character ``=''. The single ``='' character will always mean value assignment in C. Thus the result of the statements:

    x = 5;
    k = x;
is to give both x and k the value 5, while the result of the statements:
    x = 5;
    k = (x == 3);
is to give x the value 5 and k the value 0, since the relational test x == 3 is false (x is 5, not 3). Since an expression like x == 3 returns a value based on the result of the test, this value could be assigned to k in this example. Thus the result of the statement k = (x < 10) would be to set k to one, while k = (x >= 7) would assign k the value zero.

It is often useful to use multiple conditional tests to reach a branching decision. This is facilitated by the availability of the logical operators listed in decreasing order of precedence in table 2.3


Table 2.3: Some Logical Operators in C
C notation for operator Relation Binary or Unary
! logical NOT Unary
&& logical AND Binary
|| logical OR Binary

Again it is important to note that the 2-character strings ``&&'' and ``||'' are quite distinct from the 1-character strings ``&'' and ``|''. The 1-character strings represent bit-wise operations, and are not used that frequently in the kind of computing applications considered here.

The following sequence of C statements uses compound tests to handle the conditions under which the square root of y/x can be computed and returns -1 when it cannot be computed with real numbers.

    if( ( y >= 0 && x > 0 ) || ( y <= 0 && x < 0 ) ) {
        root = sqrt(y/x);
        }
    else {
        root = -1;
        }
It is important to note the fact that the precedence of each of the arithmetic operators, <, >, <= and >=, in this compound test statement is higher than the && operator, so the arithmetic tests are performed before the && operation in each case. Since the || operator has a higher precedence that the && operators, the inner level of parentheses is actually redundant to the C compiler. In this case they make the intention more apparent, and have no negative implications. In fact the pair ( and ) form an operator, as does the [ and ] pair for array element reference, with the highest precedence.

To this point, the order of evaluation of components in a C expression has been discussed in terms of operator precedence. Thus the statement

    f = x / y + (x + y) * z;
would result in the division being evaluated, followed by the sum x + y and the product of this with z, then the final addition, followed by the assignment of the resulting value to the variable f. In this example the order of evaluation was determined completely from the consideration of the precedence of the operators involved.

A complication arises when an expression contains a sequence of operations where the operators have equal precedence, so that the evaluation order cannot be determined simply from precedence. In such situations the ``tie'' is brokent by the associativity property of each operator. A common example involves the * and / operators in a C expression like

    a * b / c
Since both operators have the same precedence, the fact that both operators have left-to-right associativity must be used to determine the unique order of evaluation. In this expression the multiplication will be performed first, followed by the division. Thus the associativity properties show that the expression is equivalent to the expression
    (a * b) / c
where the parentheses enforce the order of evaluation. The result is quite different from the result of calculating
    a * (b / c)
where the division is done first, due to the very high precedence of the () pair.

Properties of the C operators of primary interest for our purposes are summarized in table 2.4 grouped in order of decreasing precedence, with their associativity properties. while this table only shows nine levels of precedence, it does not include bitwise C operators, since these are primarily of interest for systems programmers, rather than scientific programmers.


Table 2.4: Precedence and Associativity of Operators in C
Operators Binary or Unary Associativity
() [] Unary left to right
- ! & * ++ -- sizeof Unary right to left
* / % Binary left to right
+ - Binary left to right
> >= < <= Binary left to right
== != Binary left to right
&& Binary left to right
|| Binary left to right
= += -= *= /= %= Binary right to left

While it is best to know in detail the precedence level of all the operators, when there is any doubt, it is best to use parentheses to force the interpretation that you, the programmer intends. Not only does this ensure that you get what you want, but it also makes it easier for another programmer to read and understand the C programs you produce.


Cengiz Şeker
2000-12-15