c - 返回语句后的序列点?

标签 c return language-lawyer sequence-points

在我对一个问题的回答here我解释了当在与 return 语句相同的行上对全局变量使用 postfix++ 时会发生什么。

C11 的资料性附录 C 指出在 return 之后立即有一个序列点,并引用规范章节 6.8.6.4,其中找不到关于序列点的文本。

在 C 标准中的什么地方可以找到说明 return 语句后有一个序列点的规范文本?

(作为特例,我只在 7.1.4/3 找到了说明库函数的规范文本。)

最佳答案

C 2011(草案 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
+

此代码将定义行为:aFoo 中的副作用递增,并且在访问 a 之前完成,然后执行 + 。结果是a被设置为1。虽然这个“sequence point after return”规则的结果可能是0或1,但只是不确定两者中的哪一个使用命令;行为并非完全未定义。

但是,如果实现首先执行 Foo() 并使用“return 表达式和下一个完整表达式之间的顺序点”的标准 C 规则,那么我们有:

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

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

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

关于c - 返回语句后的序列点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15637678/

相关文章:

c - 使用 C 将输入写入控制台

javascript - javascript 可以读取应用程序脚本函数返回的字符串吗?

oracle - 将返回从选择查询中检索到的数据的函数 - Oracle

c++ - 静态成员函数中的 `this` 类型?

c - 未定义行为或非未定义行为

c - 在 DOS 中为 "Daylight Savings Time"

c - ASCII 值未给出正确的字母

c++ - VC++ : Form not responding during WaitForSingleObject in _tWinMain

c - 在 C 中,为什么我需要返回华氏温度?

c++ - C++ 数组上指针数学的未定义行为