序列点 "immediately before a library function returns" 的结果是什么?

What's the consequence of a sequence-point "immediately before a library function returns"?

中,一些代码显示有 未定义的行为:

a[++i] = foo(a[i-1], a[i]);

因为即使foo()的实际调用是一个序列点赋值 未排序的 ,因此您不知道函数是在 ++i 的副作用发生之后还是之前调用的。

进一步思考,函数调用中的序列点仅保证执行函数参数评估的副作用输入函数后,例如

int y = 1;
int func1(int x) { return x + y; }
int main(void)
{
    int result = func1( y++ ); // guaranteed to be 3
}

但是看看标准,还有§7.1.4 p3(在关于标准库的章节中):

There is a sequence point immediately before a library function returns.

我的问题是:这一段的结果是什么?为什么它只涉及 库函数 以及实际依赖于它的代码类型?

简单的想法,例如(遵循无意义的代码)

errno = 0;
long result = ftell(file) * errno;

仍未定义,因为这次 乘法 未排序。我正在寻找一个使用此特殊保证的示例 §7.1.4 p3 为 库函数 .


关于建议的重复,Sequence point after a return statement?,这确实是密切相关的,我在问这个问题之前就找到了。这不是重复的,因为

因此,我在这里的问题在那里没有得到解答。接受的答案在未排序的表达式中使用 return 值(在本例中为 加法 )并解释了结果如何取决于此加法的顺序,只发现 如果你知道加法的顺序,整个结果将在return之后用一个顺序点来定义。由于此规则,它没有显示实际定义的代码示例,也没有说明 how/why 库函数 是特殊的。

库函数没有标准涵盖的实现它们的代码(它们甚至可能不会在 C 中实现)。该标准仅规定了它们的行为。所以关于return语句的规定不适用于库函数的实现。

此子句的目的(结合库函数入口处的序列点)是说库函数的任何副作用在任何其他可能的评估之前或之后排序在调用库函数的代码中。

因此您问题中的示例不是未定义的行为(除非乘法溢出!):errno 的读取在 ftell 修改之前或之后排序,未指定是哪个。