在命令式编程中,序列点指的是程序执行过程中的任何一个点,在该点之前的所有运算已经产生了所有副作用,并且在该点之后的所有运算尚未产生任何副作用。
这意味着什么?请有人用简单的语言解释一下吗?
在命令式编程中,序列点指的是程序执行过程中的任何一个点,在该点之前的所有运算已经产生了所有副作用,并且在该点之后的所有运算尚未产生任何副作用。
这意味着什么?请有人用简单的语言解释一下吗?
当发生序列点时,这基本上意味着你可以保证所有之前的操作都已经完成。
在没有介入序列点的情况下两次更改变量的值是未定义行为的一个例子。
例如,i = i++;
是未定义的,因为两个对i的更改之间没有序列点。
需要注意的是,不仅是两次改变变量的值可能会导致问题。任何其他使用中涉及到的值的更改同样有可能会产生问题。在讨论如何排序事物时,标准使用“值计算和副作用”这个术语。例如,在表达式
a = i + i++
中,i
(值计算)和i++
(副作用)可能以任意顺序执行。
维基百科有一份C和C++标准规定的序列点列表,但应该始终从ISO标准中获取最权威的列表。以下是C11附录C中列出的序列点(解释经过改编):
以下是标准描述的序列点:
&&
、||
和逗号的第一个和第二个操作数的评估之间;?:
的第一个操作数和第二个和第三个操作数中的任何一个被评估之间;if
或switch
)的控制表达式;while
或 do
语句的控制表达式;for
语句中的每一个表达式;关于序列点需要注意的重要事项是它们不是全局的,而应被视为一组本地约束条件。例如,在语句
a = f1(x++) + f2(y++);
在对x++进行评估和调用f1之间存在一个序列点,并且在对y++进行评估和调用f2之间存在另一个序列点。然而,无法保证x在调用f2之前还是之后被递增,也无法保证y在调用x之前还是之后被递增。如果f1更改了y或f2更改了x,则结果将是未定义的(编译器生成的代码可以合法地读取x和y、递增x、调用f1、检查y与先前读取的值是否相同,如果已更改,则继续寻找并销毁所有巴尼视频和商品;不幸的是,我不认为任何真正的编译器会生成实际执行此操作的代码,但这在标准下是允许的)。
x = i++ * ++j;
有三个副作用:将 i * (j+1)
的结果赋值给 x,将 i 加 1,将 j 加 1。这些副作用的应用顺序是未指定的;在被评估后 i 和 j 可能会立即增加,或者它们可能在 x 被分配之前都已经被评估但尚未递增,或者它们可能在 x 被分配之后才会被递增。
序列点是所有副作用都被应用的点(x、i 和 j 都已被更新),无论它们被应用的顺序如何。
x = i++ * ++j
的结果是明确定义的,不像paxdiablo的i=i++
的例子。 - Oliver Charlesworth