C中的副作用是什么?

What is a side effect in C?

C99条款5.1.2.3第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 标准像上面那样定义了 副作用。但似乎C99并没有解释到底什么是accessing a volatile object, modifying an object, modifying a file(在clause 3中定义了什么是access, modify, object的定义。但是accessing a volatile how? modifying what object ?并修改文件的内容?)。
当我用 side effects 这个词搜索时,在 C99 中有一些例子。但我不能确定每个示例是否都属于访问 volatile 对象、修改对象和修改文件。
我读了 and Are side effects a good thing? 但还是很困惑。
我的问题是 C 标准是否明确描述了 副作用 的含义?它们是什么意思?

访问易失性对象意味着通过volatile-qualified左值读取volatile限定对象/对象的值-标准说这些需要被评估“严格 根据抽象机的规则”。

修改对象意味着修改任何对象 - 修改任何内容都被视为副作用。示例:赋值运算符具有修改其赋值的变量的副作用!在下面的程序中。赋值运算符用于其副作用!

修改文件意味着写入文件、创建文件、删除文件等等 - 任何构成更改的内容。

这些类别的副作用示例:

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

有一类(更小的)编程语言称为纯函数式语言,例如 Haskell,其计算是 side-effect 免费的。 C 不是这样的语言之一。

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

你引用的C标准(C 1999 5.1.2.3 2,C 2018同)中的那句话明确描述了side effects的含义。这些将在下面进一步解释。

修改对象

修改对象被理解为包括更新表示对象的存储字节的内容。我相信他们的完整列表是:

  • 简单赋值(=)和复合赋值(*=,/=%=,+=,-=,<<=>>=&=^=|=)。
  • 递增和递减运算符(++--),包括前缀和后缀。
  • 初始化包含在其定义中的对象。
  • 指定改变对象的库例程,例如memcpy.

访问可变对象

“访问”在 C 2018 3.1 中定义为“⟨execution-time action⟩ to read or modified the value of an object”。如果 xvolatile int,则在表达式中使用 x 的值访问它(当计算表达式时),因为它读取 x 的值。您可以更具体地遵循这一点,因为 6.3.2.1 2 告诉我们在表达式中使用 x 会导致采用 x 的值:

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.

所以表达式中的 x 本身只是对象 x 的指定,被转换为存储在 x 中的值,这意味着存储从内存中读取值。即x.

的访问

修改可变对象与修改任何对象相同,如上所述。

修改文件

通过第 7.21 条(“Input/output <stdio.h>”)中定义的例程修改文件。