c语言 - 序列点"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(在关于标准库的章节中(:

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

我的问题是:这一段的后果是什么?为什么它只涉及库函数,什么样的代码实际上依赖于它?

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

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

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


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

  • 它询问规范性文本,说明在return之后有一个序列点,而不询问当有一个序列点时的后果。
  • 它只提到了这个问题所讨论的库函数的特殊规则,没有进一步阐述。

因此,我在这里的问题在那边没有得到回答。接受的答案在非序列表达式中使用返回值(在本例中为加法(,并解释结果如何取决于此加法的顺序,只发现如果您知道加法的顺序,整个结果将在return之后立即使用序列点定义。它没有显示由于此规则而实际定义的代码示例,也没有说明库函数如何/为什么是特殊的。

库函数没有标准所涵盖的实现它们的代码(它们甚至可能不是用 C 实现的(。该标准仅指定了他们的行为。 因此,关于return语句的规定不适用于函数库函数的实现。

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

所以你问题中的例子不是未定义的行为(除非乘法溢出!(:errno的读取要么在修改之前,要么在修改之后按ftell排序,这是未指定的。

最新更新