序列点"在库函数返回之前"的结果是什么?

10 c sequence-points language-lawyer

最近的这个问题中,一些代码显示有未定义的行为:

a[++i] = foo(a[i-1], a[i]);
Run Code Online (Sandbox Code Playgroud)

因为即使实际调用foo()是一个序列点,该分配未测序,所以你不知道该功能是否被调用后的副作用不++i发生或之前.

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

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

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

库函数返回之前有一个序列点.

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

像(无意义的代码)这样​​的简单想法

errno = 0;
long result = ftell(file) * errno;
Run Code Online (Sandbox Code Playgroud)

这个时候仍然是未定义的,乘法是不确定的.我正在寻找一个利用这个特殊保证的例子§7.1.4p3使库函数成为可能.


关于建议的重复,返回语句后的序列点?这确实是密切相关的,我在问这个问题之前就找到了它.这不是重复,因为

  • 它要求有关规范性文本,说明有后立即序列点return,没有询问时,有一个后果.
  • 它只提到了这个问题所涉及的图书馆功能的特殊规则,而没有进一步详述.

因此,我在这里没有回答我的问题.接受的答案使用未序列表达式中的返回值(在这种情况下是添加)并解释结果如何取决于此添加的顺序,只发现如果您知道添加的顺序,则整个结果将定义为紧接着的序列点return.它没有显示由于此规则而实际定义的代码示例,并且没有说明库函数如何/为何如此特殊.

M.M*_*M.M 9

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

此子句的目的(与库函数的输入序列点组合)是指库函数的任何副作用在调用可能在代码中的任何其他评估之前或之后排序库函数.

所以你的问题中的例子不是未定义的行为(除非乘法溢出!):读取errno在修改之前或之后被排序ftell,它是未指定的.