1

In C99 clause 5.1.2.3 paragraph 2,

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.

C standard defines side effects like above. But It seems C99 doesn't explain what exactly is accessing a volatile object, modifying an object, modifying a file(It's defined in the clause 3 what is the definition of access, modify, object. But accessing a volatile how? modifying what object? and modifying what of a file?).
There are some examples in C99 as I search with the word side effects. But I can't be sure whether each of examples is classified among accessing a volatile object, modifying an object and modifying a file.
I read What is side effect in c? and Are side effects a good thing? but still am confused.
My question is that does the C standard explicitly describe a meaning of side effects? What they mean?

op ol
  • 705
  • 4
  • 11

2 Answers2

4

My question is that does the C standard explicitly describe a meaning of side effects?

The sentence in the C standard you quote (C 1999 5.1.2.3 2, and the same in C 2018) explicitly describes the meaning of side effects. These are further explained below.

Modifying An Object

Modifying an object is understood to include the things that update the stored bytes that represent the object. I believe a complete list of them is:

  • Simple assignment (=) and compound assignment (*=, /= %=, +=, -=, <<=, >>=, &=, ^=, and |=).
  • The increment and decrement operators (++ and --), both prefix and postfix.
  • Initialization of an object included in its definition.
  • Library routines that are specified to change objects, such as memcpy.

Accessing a Volatile Object

“Access” is defined in C 2018 3.1 as “⟨execution-time action⟩ to read or modify the value of an object”. If x is a volatile int, then using the value of x in an expression accesses it (when the expression is evaluated), because it reads the value of x. You can follow this more specifically in that 6.3.2.1 2 tells us that the use of x in an expression results in the value of x being taken:

Except when it is the operand of the sizeof operator, the unary & operator, the ++ operator, the -- operator, or the left operand of the . operator or an assignment operator, an lvalue that does not have array type is converted to the value stored in the designated object (and is no longer an lvalue); this is called lvalue conversion.

So the x in the expression which is, by itself, just a designation of the object x, is converted to the value stored in x, which means that stored value is read from memory. That is an access of x.

Modifying a volatile object is the same as modifying any object, described above.

Modifying a File

Files are modified by way of the routines defined in clause 7.21 (“Input/output <stdio.h>”).

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
1

Accessing a volatile object means reading the value of a volatile-qualified object / an object through a volatile-qualified lvalue - the standard says these need to be evaluated "strictly according to the rules of the abstract machine".

Modifying an object means modifying any object at all - modifying anything is considered a side effect. Example: an assignment operator has a side effect of modifying a variable it assigns the value to! In the following program. An assignment operator is used for its side effect!

Modifying a file means writing to the file, creating a file, deleting a file and so forth - anything that constitutes a change.

Examples of side effects from these categories:

void increment(int *p) {
    (*p) ++; // side effect - assign a new value to the 
             // object pointed to by p
}


int a = 5;
volatile int b = 6;
if (b == 6) { // side-effect of accessing a volatile variable
    a += b;   // calculate a + b, and as a side effect assign a new 
              // value to a
}

increment(&a);     // side effect - call a function that does
                   // one of the aforementioned operations
printf("%d\n", a); // side effect - change the state of an output stream

FILE *fp = fopen("foo", "w"); // side effect - create or truncate
fputc('!', fp); // side effect - modify file
fclose(fp);.    // side effect - close the file, flush 
remove("bar");. // side effect - remove file

There is a (way smaller) category of programming languages called pure functional languages, such as Haskell, whose computations are side-effect free. C is not one of such languages.

  • 1
    Not my vote, but assignments are not always used only for their side effects. `for (i = j = k = 0; …)` uses `j = k = 0` and `k = 0` for their values). – Eric Postpischil Sep 27 '20 at 13:28
  • Also, none of the examples necessarily show side effects to a file. If the stream is fully buffered, the `printf` may change only the stream, which is constructed of data structures in memory. The changes do not necessarily reach the file immediately. – Eric Postpischil Sep 27 '20 at 13:33
  • @Eric Postpischil What you want to say from `for (i = j = k = 0; ...)` uses `j = k = 0` and `k = 0`? . In this case, `=` is used for assignment to object, which causes a *side effect*(my thought). – op ol Sep 27 '20 at 13:58
  • @opol: In `i = j = k = 0`, what is assigned to `j` is the value of `k = 0`. So `0` is not directly assigned to `j`; first `k = 0` produces `0`, and then that is assigned to `j`. Similarly, what is assigned to `i` is the value of `j = k = 0`. The value of an assignment is the value that will be stored in the left operand. This is more visible in an example such as `double x; int q; x = q = 3.5;`. The assignment converts the right value to the type of the left operand, so `3.5` is converted to `3`, and `3` will be stored in `q`. So `x` receives the value 3 (the value of `q = 3.5`), not 3.5. – Eric Postpischil Sep 27 '20 at 14:11
  • @opol: Similarly, in `int x; unsigned char c; x = c = EOF;`, where `EOF` is −1, `x` would receive 255, not −1 (presuming 8-bit characters). – Eric Postpischil Sep 27 '20 at 14:13
  • @EricPostpischil: I didn't know that. But then in `i = j = k = 0`, each of three `=` causes a side effect. First 0 to k, second k to j, third j to i. You said in first comment `but assignments are not always used only for their side effects`. Is this not called as a side effect? – op ol Sep 27 '20 at 14:18
  • 1
    @opol: They are used for their side effects but not **only** for their side effects. Whenever assignments appear in a chain or the value of an assignment is otherwise used in an expression (e.g., `int c; while ((c = getchar()) != EOF)…`), they are used **also** for their values. – Eric Postpischil Sep 27 '20 at 14:21