man7.org声明有效的程序无效

在http://man7.org/linux/man-pages/man3/setbuf.3.html中给出的关于缓冲区使用function的手册中,下面的一段代码被声明为无效。 但是,当我在我的机器上尝试时,事情进展顺利:

#include  int main(void) { char buf[BUFSIZ]; setbuf(stdin, buf); printf("Hello, world!\n"); return 0; } 

这个年龄给出的理由是:

您必须确保时间流关闭时buf指向的空间仍然存在,这也会在程序终止时发生。

我在这段代码中看不出任何错误。 它也很顺利。 是对还是不对? 任何人都可以向我解释一下吗?

################################################ 2

正如@Lingxi在下面回答的那样,主函数返回后缓冲区将被销毁。 但stdin幸存了下来。

但是, stdin还有一个默认缓冲区吗? 而且,我们可以假设stdin是一个流,并且有一些方法可以销毁或关闭该流吗?

这是未定义行为的示例。 未定义的行为不是弹出的神奇错误消息,而是告诉您程序错误。 这意味着你的程序很危险。 UB可能发生的最糟糕的事情就是发生在你身上的事情 – 根本没有明显的症状。 这是因为bug未被发现,并且可能在以后导致极其危险的事情。 例如,如果在main返回之后运行的退出代码期间重新填充读缓冲区( atexit处理程序,C ++ dtors,退出时发生的stdio文件关闭等),那么堆栈上某些其他函数的返回地址可能被破坏,这可能会导致任意代码执行漏洞。

当C接口的文档告诉您无法执行某些操作时,请相信它 。 测试看它是否“有效”并不是一个有意义的活动,除非你试图弄清楚如何利用这些错误。

错误消息已经非常清楚地解释了它。 在你的代码片段中,当main返回时, buf被销毁,但是stdin的生命周期超出了main 。 在main返回之后但在stdin关闭之前的时间段内,您将打开一个带有无效缓冲区的stdin 。 这有时会引起问题。 举个例子,如果有一个全局类对象,析构函数使用stdin作为输入,你认为会发生什么?

您可能还想看看这个问题 。

这段代码失败的原因很简单,因为缓冲区是在main函数内部声明的,当这个函数结束时,因为缓冲区是main函数的本地,并且在堆栈中它被释放。 这导致atexitstream刷新和关闭不符合具有有效缓冲区的setbuf函数要求。

希望这有助于http://en.cppreference.com/w/c/language/main_function

要点是,main()实际上既不是为程序执行的第一个代码,也不是最后一个代码。 有一些“启动”代码在执行一些处理后调用main()并在main()返回后清理。

此清理的一个步骤实际上是刷新缓冲区并关闭尚未被应用程序关闭的文件(这些文件包括stdin等)。 因此,如果你离开main(),缓冲区就不再是你的了,但是清理可能仍然想要访问它。 试着把缓冲区给别人,把其他东西放进去。 任何事情都可能发生,因为你不知道他对记忆做了什么。

简单地说:C标准中用于“任何可能发生的事情”的术语是“未定义的行为”。 从字面上理解这两个短语。 @R。 指出相当不错。 想想一辆刹车不起作用的汽车,但你没有得到任何通知,开着200km / h(是 – 高速公路;-)下坡。