C 2011 (draft n1570) 6.8 4:“以下每一项都是完整的表达式:……return 语句中的(可选)表达式。在完整表达式的求值和要求值的下一个完整表达式的求值之间存在一个序列点。”
所以从技术上讲,序列点不在 return 之后,而是在 return 中的表达式评估和下一个表达式之间。考虑这段代码,当a 最初为 0 时调用:
int a = 0;
int Foo(void) { return a++; }
void Bar(void)
{
int b = Foo() + a;
…
}
在Foo() + a 中,未指定首先评估Foo() 还是a。我们将根据两个潜在规则(return 之后的序列点与 return 表达式和下一个完整表达式之间的序列点)来考虑这两个顺序。如果实现首先执行a,那么它必须执行:
a
Sequence point
Foo()
+
然后会出现其他一些完整的表达式,因此,根据任一规则,都会有一个序列点,就我们而言,无论哪种方式,这段代码都是相同的。结果是b被设置为0。
如果实现首先执行Foo(),那么,使用“return之后的序列点”规则,实现必须这样做:
Sequence point
Foo()
Sequence point
a
+
此代码将定义行为:a 由Foo 中的副作用递增,并且在访问a 之前完成,然后执行+。结果是a被设置为1。虽然使用“return之后的顺序点”规则,结果可能是0或1,但只是未指定使用两个顺序中的哪一个;行为并非完全未定义。
但是,如果实现首先执行 Foo() 并使用标准 C 规则“return 表达式和下一个完整表达式之间的序列点”,那么我们有:
Sequence point
Foo()
???
a
???
+
???
“???”标记可能需要的序列点的位置——return 之后和下一个完整表达式之前的任何位置。在这种情况下,a 的值可能会在a 中访问并在Foo() 中修改,并且没有中间序列点。那是未定义的行为。
因此,“return表达式之后的序列点,下一个完整表达式之前的序列点”规则与“return之后的序列点”不同;在此示例中,第一个具有未定义的行为,而第二个则没有。