当我阅读的文档时fflush,它说如果成功则返回 0,否则返回 EOF(我的机器上的 EOF 为 -1)。(请参阅

因此我创建了以下示例:

#include<cstdio>
#include<iostream>

int main()
{
    FILE* fp = std::fopen("/tmp/test", "w+");
    std::fclose(fp);

    std::cout << std::fflush(fp) << std::endl;
    return 0;
}

g++ minimal.cpp如果我使用或进行编译g++ -O2 -DNDEBUG minimal.cpp,它会打印 -1。这正是我所期望的。

g++ minimal.cpp -fsanitize=address但是,当我用或编译它时g++ minimal.cpp -fsanitize=thread,它只打印 0。

我也可以用 clang 重现同样的问题。

怎么会这样?

我在我的 Debian 12 amd64 机器上使用了 g++-12 和 clang-15。结果始终相同(即fflush返回 0 而不是 -1)。

1

  • std::fflush(fp)无论使用什么清理器,之后std::fclose(fp)都是 UB:对流的任何进一步访问都会导致未定义的行为。


    – 



最佳答案
1

根据 fflush 的文档(C99 标准中的 7.19.5.2):

如果 stream 指向一个输出流或一个未输入最近操作的更新流,则 fflush 函数会导致将该流的任何未写入数据传送到主机环境并写入文件;否则,行为未定义。

这意味着如果您在未打开的文件上调用它(就像您正在做的那样),您会得到未定义的行为。

这是因为 C 标准在历史上是一个“事实上的”标准,它收集了不同实现所做的所有常见事情,而不是试图“强迫”不同的实现者实现相同的事情。因此,在很多地方(尤其是错误或极端情况),不同的实现在历史上做了不同的事情,所以标准只是说“未定义”。

5

  • 的链接可能对 OP 有用,因此添加到这里。


    – 

  • @JesperJuhl C 中是否有类似的 UB 描述?尽管 C 和 C++ 对未定义行为的概念非常相似,但仍存在一些关键差异。并且本例中的未定义行为源自 C 标准,而非 C++ 标准。


    – 

  • @peter 它们是相同的概念。C:“使用不可移植或错误的程序构造或错误数据时的行为,本国际标准对此不作要求”;C++:“本文档对此不作要求的行为”。


    – 

  • @molbdnilo 我知道定义是相同的。但 Jesper 给出的链接也讨论了其含义,并提供了涉及 C++ 代码的具体示例。考虑到这里的人们经常因为询问有关 C 和 C++ 的问题而大吵大闹,而且这个答案引用了 C 标准,如果有与 C 相关的信息(在这种情况下我不知道) – 将是合适的。


    – 

  • @Peter是关于 C 的相应页面。


    –