c-POSIX说stderr应该是开放读写的,这是什么意思



POSIX在stderr、stdin、stdout上的页面-标准I/O流显示:

stderr流应打开以进行读取和写入。

"预期"有多强?违反它是未定义的行为吗?这是谁的责任,是系统的责任还是应用程序的责任?

考虑一下这个程序:

#include <stdio.h>
int main(void) {
printf("feof is %d and ferror is %dn", feof(stderr), ferror(stderr));
printf("fgetc is %dn", fgetc(stderr));
printf("feof is %d and ferror is %dn", feof(stderr), ferror(stderr));
}

当我在不重定向stderr的情况下运行它时(所以它像stdin一样指向我的终端),它会立即输出,而不等待任何输入:

feof is 0 and ferror is 0
fgetc is -1
feof is 0 and ferror is 1

这是否意味着我的系统不符合POSIX?

此外,如果这是我的责任,那么假设我有一个权限为620的文件,并且我在组中,但不是所有者。这是否意味着someprogram 2>saidfile是未定义的行为,因为在这种情况下无论如何都无法从stderr读取?

奥斯汀小组(维护POSIX标准的联合工作组)讨论了关于";预期为";2020-12-07年和2020-12-10年电视转播期间的措辞,并同意POSIX第7期(2018年版)中的措辞存在问题。在POSIX标准的下一个版本中,措辞将更改如下(从错误注释中复制):

在第65页第1912行(XBD"交互式shell")之前插入一个新的定义,并对剩余的进行重新编号:

交互式设备

一种终端设备。

注:此定义旨在与ISO C标准对";交互式设备";。

在第496页第17224-17228行(XSH 2.5标准I/O流)和第2017页第64723-64727行(XSH-stderr、stdin、stdout描述)更改:

在程序启动时,应预定义三个流,无需显式打开:标准输入(用于读取常规输入)、规范输出[用于写入常规输出]和标准错误[用于写入诊断输出]。打开时,标准错误流未完全缓冲;当且仅当可以确定流不涉及交互式设备时,标准输入流和标准输出流被完全缓冲。

到:

在程序启动时,应预定义并已打开三个流:用于读取的stdin(标准输入,用于常规输入)、用于写入的stdout[标准输出,用于常规输出]和用于写入的stderr[标准错误,用于诊断输出]。打开时,stderr不应被完全缓冲stdinstdout应被完全缓冲,如果且仅当[CX]与流相关联的文件描述符被确定为不与交互式设备相关联。[/CX]

在2017页第64733行(XSH stdin描述),更改:

stderr流应打开以进行读取和写入。

到:

这些文件描述符通常都与具有访问模式O_RDWR的单个打开文件描述相关联(例如,在登录外壳的终端设备的情况下)。但是,在这种情况下,不需要在程序启动时打开stderrstdin标准输出流进行读取和写入。

在2017页第64747行(标准输入另请参阅)添加isatty()。

特别感谢Rich Felker报告缺陷。

POSIX在execve:的规范中对此进行了详细阐述

如果文件描述符0、1或2在成功调用exec系列函数之一后将被关闭,则实现可能会为新进程映像中的文件描述符打开一个未指定的文件。如果在文件描述符0未打开以供读取或文件描述符1或2未打开以用于写入的情况下执行标准实用程序或符合要求的应用程序,则执行该实用程序或应用程序的环境应被视为不符合要求,因此,该实用程序或应用程序可能不会按照本标准所述进行操作。

对于您自己的应用程序,如果他们试图在关闭任何一个应用程序的情况下执行,则应该为实现为他们打开新的stdin/out/err的可能性做好准备,并且可以设置自己的规则(包括将其视为违反合同导致灾难性错误行为),以便在标准文件描述符启动时未打开时如何处理。

对于标准实用程序,上面的文本涵盖了它。

您引用的文档只是指定它们与那些文件描述符相关联。我同意这还不够清楚,但合理的解释是,如果相应的文件描述符在应用程序输入时没有打开或没有为适当的模式打开,那么结果就是在相关函数下为该条件指定的结果(通常是EBADF)。例如,fgetc指定:

[EBDF]

[CX][Option Start]流的文件描述符不是打开以供读取的有效文件描述符。[选项结束]

关于"预期"文本:

stderr流应打开以进行读取和写入。

我不认为"预期"在标准中的任何地方都有定义。然而,这里使用的是这个词,而不是文件/文件描述符,所以我认为stderr流的FILE模式(如在fopen模式中)是这样的,只要遵守关于在它们之间切换的规则,它上的读和写函数都不会产生未定义的行为。如果没有这个文本,例如在没有POSIX的情况下,fgetc(stderr)可能会产生未定义的行为。

最新更新