return 语句之后的序列点?

Lun*_*din 3 c return sequence-points language-lawyer

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

C11的资料性附录C指出a之后紧接着有一个序列点return,并参考规范性章节6.8.6.4,其中找不到有关序列点的文本。

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

(我只在 7.1.4/3 找到了针对库函数说明这一点的规范文本,作为一种特殊情况。)

Eri*_*hil 5

C 2011 (draft n1570) 6.8 4: \xe2\x80\x9c 以下各项是完整表达式: \xe2\x80\xa6 return语句中的(可选)表达式。在完整表达式的计算和下一个要计算的完整表达式的计算之间存在一个序列点。\xe2\x80\x9d

\n

因此从技术上讲,序列点不是在返回之后,而是在返回中的表达式的计算与下一个表达式之间。考虑这段代码,当a最初为 0 时调用:

\n
int a = 0;\n\nint Foo(void) { return a++; }\n\nvoid Bar(void)\n{\n    int b = Foo() + a;\n    \xe2\x80\xa6\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
a\nSequence point\nFoo()\n+\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

如果实现Foo()首先执行此操作,则在 return \xe2\x80\ x9d规则之后使用 \xe2\x80\x9csequence 点,实现必须执行以下操作:

\n
Sequence point\nFoo()\nSequence point\na\n+\n
Run Code Online (Sandbox Code Playgroud)\n

该代码将具有定义的行为:a通过 中的副作用递增,并且在访问Foo之前完成,然后执行。结果是被设置为 1。尽管在return \xe2\x80\x9d 规则之后,这个 \xe2\x80\x9c 序列点的结果可能是 0 或 1 ,但只是未指定使用这两个顺序中的哪一个;该行为并非完全未定义。a+a

\n

然而,如果实现首先执行并使用标准 C 规则 \xe2\x80\x9c返回Foo()表达式和下一个完整表达式 \xe2\x80\x9d 之间的序列点,那么我们有:

\n
Sequence point\nFoo()\n???\na\n???\n+\n???\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

因此,规则 \xe2\x80\x9c 在 return 表达式之后下一个完整表达式 \xe2\x80\x9d 之前的序列点与紧接在 return \xe2\x80\x9d 之后的 \xe2 \ x80\x9c 序列点不同;在此示例中,第一个具有未定义的行为,而第二个则没有。

\n