side effect and sequence point

"side effect" is defined in C99 5.1.2.3

Accessing a volatile object, modifying an object, modifying a file, or calling a function

that does any of those operations are all side effects, which are changes in the state of

the execution environment. Evaluation of an expression may produce side effects.

"sequence point" is also defined in C99 5.1.2.3

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.)

Following is the Annex C of C99, a list of sequence points:

  • The call to a function, after the arguments have been evaluated.
  • The end of the first operand of the following operators: logical AND &&; logical OR ||; conditional ?; comma ,
  • The end of a full declarator;
  • The end of a full expression: an initializer; the expression in an expression statement; the controlling expression of a selection statement (if or switch); the controlling expression of a while or do statement; each of the expressions of a for statement; the expression in a return statement.
  • Immediately before a library function returns.
  • After the actions associated with each formatted input/output function conversion specifier.
  • Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call.

Why sequence point is important?

Sequence point is a very important concept for the following two reasons:

1. it determine the sequence of the code execution. E.g.,

a = 1;

a = 3;

here "a=1" is a full expression terminated by semicolon ";" punctuator at the end of the line. Therefore the semicolon ";" punctuator suggests the "end of a full expression", which is a sequence point.

here is the definition of "expression" in C99:

C99 section 6.5:

An expression is a sequence of operators and operands that specifies computation of a

value, or that designates an object or a function, or that generates side effects, or that

performs a combination thereof.

C language sequence point demand that any implementation must execute first line (if its optimizer determined to do so) and complete it before execute second line, because there is a semicolon ";" punctuator between two lines, which is a sequence point.

2. it determines that some of the compiler optimization is irrelevant:

C99, section 5.1.2.3:

The semantic descriptions in this International Standard describe the behavior of an

abstract machine in which issues of optimization are irrelevant.

the optimization between sequence point is irrelevant, optimization must be done within sequence point.

for example:

int a = 1;

while (a !=0) { /* this is a sequence point. refer Annex C: ...the controlling expression of a while or do statement.... */

sleep(10);

}

because "int a =1" is a full expression, variable "a" would have value of 1 before the execution of while() begins. A compiler can choose to optimize the while loop into the below code:

while ( 1 != 0 ) {

sleep(10);

}

above code will sleep forever.

let's take a look at another example:

printf("%d\n", (a=3));

"a=3" is an expression, the side effect of it is that it "produced a rvalue" of 3.

let's take another example:

a = b = 3;

above will try to assign variable "a" to a value determined by "assignment expression "b=3". As we know, "b=3" will be evaluated and will produce a side effect of "a rvalue of 3", hence variable "a" will have a value of 3 after the semicolon punctuator, which signal a "sequence point" as "the end of a full expression".

let's take a look at another example:

int a = 1;

printf("%d %d\n", a, a++);

the only sequence point in the second statement is the semicolon punctuator that signal "the end of a full expression", therefore the order of the execution of "a" and "a++" are not deterministic, C99 does not demand any ordering of them. The execution of the above code could produce:

1,2

or

2,2

let's take another example:

printf("%d %d %d\n", (a=3), (a=2), (a=1));

the only sequence point in the above code is the semicolon punctuator that signal "the end of a full expression", therefore the order of the execution of (a=3), (a=2), (a=1) are not deterministic, C99 does not demand any ordering of them. the value of variable "a" can be any value among "1", "2", and "3".

the execution of the above statement may produce:

2,2,2

or

1,1,1

or

3,3,3

Summary: a sequence point is a point where all the execution of earlier code has completed and all side effects have taken place, the execution of the code after the sequence has not taken place.