Expression Evaluation

Expressions involving assignment, unary increment, unary decrement, or calling a function may have consequences incidental to their evaluation (side effects). When a “sequence point” is reached, everything preceding the sequence point, including any side effects, is guaranteed to have been evaluated before evaluation begins on anything following the sequence point.

“Side effects” are changes caused by the evaluation of an expression. Side effects occur whenever the value of a variable is changed by an expression evaluation. All assignment operations have side effects. Function calls can also have side effects if they change the value of an externally visible item, either by direct assignment or by indirect assignment through a pointer.

Side Effects

The order of evaluation of expressions is defined by the specific implementation, except when the language guarantees a particular order of evaluation (as outlined in “Precedence and Order of Evaluation”). For example, side effects occur in the following function calls:

add( i + 1, i = j + 2 );

myproc( getc(), getc() );

The arguments of a function call can be evaluated in any order. The expression i + 1 may be evaluated before i = j + 2, or i = j + 2 may be evaluated before i + 1. The result is different in each case. Likewise, it is not possible to guarantee what characters are actually passed to the myproc. Since unary increment and decrement operations involve assignments, such operations can cause side effects, as shown in the following example:

x[i] = i++;

In this example, the value of x that is modified is unpredictable. The value of the subscript could be either the new or the old value of i. The result can vary under different compilers or different optimization levels.

Since C does not define the order of evaluation of side effects, both evaluation methods discussed above are correct and either may be implemented. To make sure that your code is portable and clear, avoid statements that depend on a particular order of evaluation for side effects.

Sequence Points

Between consecutive “sequence points” an object's value can be modified only once by an expression. The C language defines the following sequence points:

Left operand of the logical AND operator (&&). The left operand of the logical AND operator is completely evaluated and all side effects complete before continuing. If the left operand evaluates to false (0), the other operand is not evaluated.

Left operand of the logical OR operator (||). The left operand of the logical OR operator is completely evaluated and all side effects complete before continuing. If the left operand evaluates to true (nonzero), the other operand is not evaluated.

Left operand of the comma operator. The left operand of the comma operator is completely evaluated and all side effects complete before continuing. Both operands of the comma operator are always evaluated. Note that the comma separating arguments in a function call do not guarantee an order of evaluation.

Function-call operator. All arguments to a function are evaluated and all side effects complete prior to entry to the function. No order of evaluation among the arguments is specified.

First operand of the conditional operator. The first operand of the conditional operator is completely evaluated and all side effects complete before continuing.

The end of a full initialization expression (that is, an expression that is not part of another expression).

The expression in an expression statement. Expression statements consist of an optional expression followed by a semicolon (;). The expression is evaluated for its side effects and there is a sequence point following this evaluation.

The controlling expression in a selection (if or switch) statement. The expression is completely evaluated and all side effects complete before the code dependent on the selection is executed.

The controlling expression of a while or do statement. The expression is completely evaluated and all side effects complete before any statements in the next iteration of the while or do loop are executed.

Each of the three expressions of a for statement. The expressions are completely evaluated and all side effects complete before any statements in the next iteration of the for loop are executed.

The expression in a return statement. The expression is completely evaluated and all side effects complete before control returns to the calling function.