【发布时间】:2018-01-30 13:25:25
【问题描述】:
在this recent question 中,显示某些代码具有未定义的行为:
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 为库函数制作的特殊保证的示例。
关于建议的重复,Sequence point after a return statement?,这确实是密切相关的,我在问这个问题之前发现了它。这不是重复的,因为
- 它询问规范性文本,说明是紧跟在
return之后的序列点,而不询问有序列点时的后果。 - 它只提到了库函数的特殊规则这个问题是关于,没有进一步详细说明。
因此,我在这里的问题在那里没有得到回答。接受的答案在未排序的表达式中使用返回值(在本例中为 addition)并解释结果如何取决于此加法的顺序,仅发现 如果您知道 加法的顺序,整个结果将在return 之后立即定义一个顺序点。它没有显示由于该规则而实际定义的代码示例,也没有说明库函数如何/为什么特别。
【问题讨论】:
-
“标准免责声明”:如果您因为我错过了一些“显而易见的”而投反对票,请发表评论指出,谢谢。
-
@MichaelFoukarakis 我检查了那个,它密切相关,但没有回答 this 问题。虽然这里提到了特殊的库函数规则,但没有任何代码示例该规则实际上有任何效果。
-
该语句的实际使用是在程序中使用多线程时。
-
@hacks 我猜肯定还有别的原因,因为在 C99 中已经找到了相同的段落。
标签: c language-lawyer sequence-points