在我对一个问题的回答中,我解释了在与return
语句在同一行的全局变量上使用后缀 ++ 时发生的情况。
C11 的资料性附录 C 指出在 a 之后有一个序列点,return
并参考规范性章节 6.8.6.4,其中没有关于序列点的文本。
在 C 标准中,我可以在哪里找到说明语句后有序列点的规范性文本return
?
(作为特例,我只在 7.1.4/3 找到了说明库函数的规范文本。)
在我对一个问题的回答中,我解释了在与return
语句在同一行的全局变量上使用后缀 ++ 时发生的情况。
C11 的资料性附录 C 指出在 a 之后有一个序列点,return
并参考规范性章节 6.8.6.4,其中没有关于序列点的文本。
在 C 标准中,我可以在哪里找到说明语句后有序列点的规范性文本return
?
(作为特例,我只在 7.1.4/3 找到了说明库函数的规范文本。)
C 2011 (draft n1570) 6.8 4:“以下每一项都是完整的表达式:…… return语句中的(可选)表达式。在完整表达式的求值和要求值的下一个完整表达式的求值之间存在一个序列点。”</p>
所以从技术上讲,序列点不是在返回之后,而是在返回中表达式的评估和下一个表达式之间。考虑这段代码,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
+
此代码将具有定义的行为:a
由 中的副作用递增Foo
,并且在访问之前完成a
,然后+
执行。结果是设置为1。虽然使用“返回a
后的序列点”规则,结果可能是0或1,但它只是未指定使用两个顺序中的哪一个;行为并非完全未定义。
但是,如果实现首先执行并使用“返回Foo()
表达式和下一个完整表达式之间的序列点”的标准 C 规则,那么我们有:
Sequence point
Foo()
???
a
???
+
???
这 ”???” 标记可能需要的序列点的位置——返回之后和下一个完整表达式之前的任何地方。在这种情况下, 的值a
可能在 中被访问a
和修改Foo()
,并且没有中间序列点。那是未定义的行为。
因此,规则“一个return表达式之后和下一个完整表达式之前的序列点”与“一个return之后的序列点”是不同的;在此示例中,第一个具有未定义的行为,而第二个则没有。
我不认为你会找到你要找的东西。no text regarding sequence points can be found
确实如此,它仅在第 6.8 p4 节中有所暗示。
第 1.9 节(脚注 11)中的 C++ 标准(ISO/IEC 14882:2003)声明了返回后的序列点在 C 标准中的任何地方都没有明确写入的事实:
11) 函数返回处的序列点在 ISO C 中没有明确指定,可以认为与完整表达式处的序列点是多余的,但额外的清晰性在 C++ 中很重要。在 C++ 中,被调用的函数可以通过多种方式终止其执行,例如抛出异常。