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

标签 c language-lawyer sequence-points

this recent question , 一些代码被证明有未定义的行为:

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

因为即使foo() 的实际调用序列点赋值 也是< em>无序,所以你不知道函数是在 ++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? ,这确实是密切相关的,我在问这个问题之前就发现了。它不是重复的,因为

  • 它询问规范文本,说明 isreturn 之后立即有一个序列点,而不询问有一个序列点时的后果。
  • 只是提到了这个问题所涉及的库函数的特殊规则,没有进一步阐述。

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

最佳答案

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

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

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

关于c - 序列点 "immediately before a library function returns"的结果是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45814572/

相关文章:

c - 程序在用户输入后结束

c - tolower() 函数问题

c++ - 如何在 C 中以确定的概率处理命令?

c - 在动态分配的内存上使用指针算法的未定义行为

c - 分号真的是C中的一个序列点吗?

c - 在 C99 中,f()+g() 是未定义的还是仅仅是未指定的?

c++ - 静态类成员是否保证在调用 `main` 之前被初始化?

c++ - 项目符号 [dcl.init]/7 (7.1)

c - 为什么这些构造使用前后递增的未定义行为?

c - 在 C 中调用函数时的序列点和未定义/未指定的行为