## Code Examples

A particular type of question comes up often in C programming forums. Here is an example of such a question:

    #include <stdio.h>

    int main()
    {
        int i = 5;
        printf("%d %d %d\n", i, i--, ++i);
        return 0;
    }

On my system, the output was `5 6 5` with GCC and `6 6 6` with the C compiler that came with Microsoft Visual Studio. The versions of the compilers with which I got these results are:

- gcc (Debian 4.3.2-1.1) 4.3.2
- Microsoft Visual Studio 2005 32-Bit C/C++ Optimizing Compiler Version 14.00.50727.42 for 80x86

Here is another example of such a question:

    #include <stdio.h>

    int main()
    {
        int a = 5;
        a += a++ + a++;
        printf("%d\n", a);
        return 0;
    }

In this case, I got the output `17` with both these compiler versions.

The behaviour of such C programs is undefined. Consider the following two statements:

- `printf("%d %d %d\n", i, i--, ++i);`
- `a += a++ + a++;`

We will see below that in both statements, the variable is modified more than once between two consecutive sequence points. If the value of a variable is modified more than once between two consecutive sequence points, the behaviour is undefined. Such code may behave differently when compiled with different compilers.

## K&R

Before looking at the relevant sections of the C99 standard, let us see what the book The C Programming Language, Second Edition says about such C statements. In Section 2.12 (Precedence and Order of Evaluation) of the book, the authors write:

> C, like most languages, does not specify the order in which the operands of an operator are evaluated. (The exceptions are `&&`, `||`, `?:`, and '`,`'.) For example, in a statement like

>     x = f() + g();

> `f` may be evaluated before `g` or vice versa; thus if either `f` or `g` alters a variable on which the other depends, `x` can depend on the order of evaluation. Intermediate results can be stored in temporary variables to ensure a particular sequence.

Note that the comma (`,`) mentioned here is the comma operator, not the comma that separates function arguments. In the next paragraph, they write,

> Similarly, the order in which function arguments are evaluated is not specified, so the statement

>     printf("%d %d\n", ++n, power(2, n));    /* WRONG */

> can produce different results with different compilers, depending on whether `n` is incremented before `power` is called. The solution, of course, is to write

>     ++n;
>     printf("%d %d\n", n, power(2, n));

They provide one more example in this section:

> One unhappy situation is typified by the statement

>     a[i] = i++;

> The question is whether the subscript is the old value of `i` or the new. Compilers can interpret this in different ways and generate different answers depending on their interpretation.

## C99

To read more about this, download the C99 standard and go to section 4 (Conformance) and read the second point:

> If a "shall" or "shall not" requirement that appears outside of a constraint is violated, the behavior is undefined. Undefined behavior is otherwise indicated in this International Standard by the words "undefined behavior" or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe "behavior that is undefined".

Next go to section 5.1.2.3 (Program execution) and see the second point which mentions:

> Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects,11) which are changes in the state of the execution environment. Evaluation of an expression may produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place. (A summary of the sequence points is given in annex C.)

Then go to section 6.5 and see the second point which mentions:

> Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression.72) Furthermore, the prior value shall be read only to determine the value to be stored.73)

Finally go to Annex C (Sequence Points). It lists all the sequence points. For example, the following is mentioned as a sequence point:

> The call to a function, after the arguments have been evaluated (6.5.2.2).

This means that in the statement

    printf("%d %d %d\n", i, i--, ++i);

there is a sequence point after the evaluation of the three arguments (`i`, `i--` and `++i`) and before the `printf()` function is called. But there is no sequence point between the evaluations of the individual arguments. Yet the value of `i` is modified more than once during the evaluation of these arguments. This makes the behaviour of this statement undefined. Further, the value of `i` is being read not only for determining what it must be updated to but also for using as arguments to the `printf()` call. This also makes the behaviour of this code undefined.

Let us see another example of a sequence point from Annex C.

> The end of a full expression: an initializer (6.7.8); the expression in an expression statement (6.8.3); the controlling expression of a selection statement (`if` or `switch`) (6.8.4); the controlling expression of a `while` or `do` statement (6.8.5); each of the expressions of a `for` statement (6.8.5.3); the expression in a `return` statement (6.8.6.4).

Therefore in the statement

    a += a++ + a++;

there is a sequence point at the end of the complete expression (marked with a semicolon) but there is no other sequence point before it. Yet the value of `a` is modified more than once before the sequence point. Thus the behaviour of this statement is undefined.