返回语句后的序列点?

时间:2013-03-26 12:58:44

标签: c return language-lawyer sequence-points

在我对问题here的回答中,我解释了当postfix ++在与return语句相同的行上的全局变量上使用时发生的事情。

C11的资料性附录C表明在return之后有一个序列点,并且参考规范性章节6.8.6.4,其中没有关于序列点的文本。

在C标准中我可以找到规范性文本,说明return语句后有一个序列点吗?

(我只发现规范性文本说明了这个库函数,作为特殊情况,在7.1.4 / 3。)

2 个答案:

答案 0 :(得分:4)

C 2011(draft n1570)6.8 4:“以下各项均为完整表达式:... 返回语句中的(可选)表达式。在评估完整表达式和评估下一个要评估的完整表达式之间存在一个序列点。“

从技术上讲,序列点不是在返回之后,而是在 return 中的表达式和下一个表达式的评估之间。考虑这个代码,在a最初为0时调用:

int a = 0;

int Foo(void) { return a++; }

void Bar(void)
{
    int b = Foo() + a;
    …
}

Foo() + a中,首先评估Foo()a是否未指定。我们将根据两个潜在规则(返回之后的序列点与返回的表达式和下一个完整表达式之间的序列点)来考虑两个订单。如果实现首先a,则必须执行:

a
Sequence point
Foo()
+

然后会有一些其他的完整表达式,因此,根据任一规则,都会有一个序列点,就我们而言,这个代码都是相同的。结果是b设置为0。

如果实现首先Foo(),那么,使用“返回”规则后的“序列指针”,实现必须执行:

Sequence point
Foo()
Sequence point
a
+

此代码将定义行为:aFoo中的副作用增加,并且在访问a之前完成,然后执行+。结果是a设置为1.虽然结果可能是0或1,这个“返回之后的序列点”规则,但仅仅未指定使用这两个订单中的哪一个;行为并非完全未定义。

但是,如果实现首先执行Foo()并使用标准C规则“返回的表达式与下一个完整表达式之间的序列点”,那么我们有:< / p>

Sequence point
Foo()
???
a
???
+
???

“???”标记位于返回之后和下一个完整表达式之前所需的序列点所在的位置。在这种情况下,a的值可以在a中访问,并在Foo()中修改,并且没有中间序列点。这是未定义的行为。

因此,规则“表达返回之后和下一个完整表达之前的序列点”与“返回之后的序列点”不同;第一个在这个例子中有未定义的行为,第二个没有。

答案 1 :(得分:4)

我认为你不会找到你想要的东西。 no text regarding sequence points can be found这是真的,这只是第6.8节第4节所暗示的。

第1.9节(脚注11)中的C ++标准(ISO / IEC 14882:2003)规定了返回后的序列点明确地写在C标准中的任何地方:

  

11)函数返回的序列点未在ISO C中明确指定,并且可以被视为冗余序列   指向全表达式,但额外的清晰度在C ++中很重要。在C ++中,被调用函数可以通过多种方式终止   它的执行,例如抛出异常。