在this recent question中,某些代码显示未定义的行为:
a[++i] = foo(a[i-1], a[i]);
因为即使foo()
的实际调用是序列点,分配 未经过排序 em>,因此您不知道在++i
的副作用发生之后或之前是否调用了该函数。
进一步考虑这一点,函数调用中的序列点仅保证在输入函数后执行副作用评估函数参数,例如< / p>
int y = 1;
int func1(int x) { return x + y; }
int main(void)
{
int result = func1( y++ ); // guaranteed to be 3
}
但是看看标准,还有§7.1.4p3(在关于标准库的章节中):
库函数返回之前有一个序列点。
我的问题是:这一段的结果是什么?为什么它只涉及库函数以及实际依赖的代码类型?
简单的想法,如(无意义的代码可以遵循)
errno = 0;
long result = ftell(file) * errno;
仍然未定义为此时,乘法未被排序。我正在寻找一个利用这个特殊保证的例子§7.1.4p3使库函数。
关于建议的副本Sequence point after a return statement?,这确实是密切相关的,我在问这个问题之前就找到了它。这不是重复,因为
return
之后的序列点,而没有询问有没有后果的情况。因此,我的问题在那里没有得到解答。接受的答案使用未序列表达式中的返回值(在本例中为添加),并解释结果如何取决于此添加的顺序,只发现如果您知道加法的排序,整个结果将在return
之后立即用序列点定义。它没有显示由于此规则而实际定义的代码示例,并且没有说明如何/为什么库函数是特殊的。
答案 0 :(得分:9)
库函数没有标准所涵盖的实现它们的代码(它们甚至可能不在C中实现)。标准仅指定其行为。因此,关于return
语句的规定不适用于库函数的实现。
本条款的目的(与库函数的输入序列点相结合)是指库函数的任何副作用在可能在其中的任何其他评估之前或之后排序。调用库函数的代码。
因此,您的问题中的示例不是未定义的行为(除非乘法溢出!):errno
的读取在ftell
修改之前或之后排序,未指定哪一个。