我编写了一个创建空文本文件的程序,如果成功则打印Succeed
。
使用cc main.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
int main()
{
int fd;
// Create empty text file
fd = open("foo.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
assert(fd != -1);
fprintf(stderr, "File descriptor is %d\n", fd);
printf("Succeed\n");
}
使用./a.out
使用./a.out >&-
运行时,open()
会返回1,我理解。
但是,printf
正在写入我的文件!
$ cat foo.txt
Succeed
我不想这样,所以我写了以下内容:
int main()
{
int fd1;
int fd2;
int fd3;
int fd4;
fd1 = open("foo.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
assert(fd1 != -1);
fd2 = open("foo.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
assert(fd2 != -1);
fd3 = open("foo.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
assert(fd3 != -1);
fd4 = open("foo.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
assert(fd4 != -1);
int final_fd = fd4;
close(fd1);
close(fd2);
close(fd3);
fprintf(stderr, "File descriptor is %d\n", final_fd);
printf("Standard output\n");
}
效果很好,printf
会失败并返回-1但我不在乎。
我知道我可以通过检查open()
返回值是否大于或等于3进行优化,但这只是一个例子。
使用./a.out >/dev/null
有效但不是解决方案,我不能禁止我的程序用户关闭标准输出。
这是解决问题的正确方法吗?
答案 0 :(得分:3)
在POSIX open
上总是返回最小的可用文件描述符。您可以处理此问题的唯一方法是在程序开头检查文件描述符0 ... 2与isatty
说 - 如果isatty
返回0 和 {{ 1}}设置为errno
,文件描述符未被使用,然后应该从EBADF
打开一个新的描述符:
/dev/null
另请注意,未打开的流的状态根本不符合标准。 C11 7.21.3p7:
7在程序启动时,预定义了三个文本流,无需明确打开 - 标准输入(用于读取常规输入),标准输出(用于写入常规输出)和标准错误(用于写入诊断输出)。最初打开时,标准错误流未完全缓冲;当且仅当可以确定流不参考交互设备时,标准输入和标准输出流被完全缓冲。
这可能被视为C启动例程中的失败 - 在我看来,它应该至少将这些流打开到for (int fd = 0; fd <= 2; fd++) {
errno = 0;
if (! isatty(fd) && errno == EBADF) {
open("/dev/null", O_RDWR);
}
}
虽然现在我尝试了这个,但我得出的结论是,运行标准流关闭的程序不仅受到脑损伤,而且完全是脑死亡,因为任何/dev/null
也会打开{{1} },fopen
或stdin
,所以我将代码修改为:
stdout