如何处理 open() 返回 1
How to deal with open() returning 1
我编写了一个创建空文本文件的程序,如果成功则打印 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
时效果很好
when 运行 with ./a.out >&-
, open()
returns 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
会失败并且 return -1 但我不在乎。
我知道我可以通过检查 open()
return 值是否大于或等于 3 来优化,但这只是一个例子。
使用 ./a.out >/dev/null
可行但不是解决方案,我不能禁止我的程序的用户关闭标准输出。
这是处理问题的正确方法吗?
在 POSIX open
上 总是 return 最小的可用文件描述符。处理这个问题的唯一方法是在程序的开头检查文件描述符 0 ... 2 说 isatty
- if isatty
returns 0 并且 errno
设置为 EBADF
,文件描述符未被使用,然后应该从 /dev/null
:
打开一个新的描述符
for (int fd = 0; fd <= 2; fd++) {
errno = 0;
if (! isatty(fd) && errno == EBADF) {
open("/dev/null", O_RDWR);
}
}
另请注意,那些未打开的流的状态根本不符合标准。 C11 7.21.3p7:
7 At program startup, three text streams are predefined and need not be opened explicitly -- standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.
这可以被认为是 C 启动例程中的一个失败 - 在我看来,它应该至少 /dev/null
打开这些流
虽然现在我尝试了这个,但我得出的结论是 运行 关闭标准流的程序不仅脑损伤而且完全脑死亡,因为任何 fopen
也会打开 stdin
、stdout
或 stderr
,所以我将代码修改为:
struct stat statbuf;
for (int fd = 0; fd <= 2; fd++) {
if (fstat(fd) == 0 && errno == EBADF) {
fprintf(stderr, "Id10t error: closed standard IO descriptor %d\n", fd);
abort();
}
}
我编写了一个创建空文本文件的程序,如果成功则打印 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
when 运行 with ./a.out >&-
, open()
returns 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
会失败并且 return -1 但我不在乎。
我知道我可以通过检查 open()
return 值是否大于或等于 3 来优化,但这只是一个例子。
使用 ./a.out >/dev/null
可行但不是解决方案,我不能禁止我的程序的用户关闭标准输出。
这是处理问题的正确方法吗?
在 POSIX open
上 总是 return 最小的可用文件描述符。处理这个问题的唯一方法是在程序的开头检查文件描述符 0 ... 2 说 isatty
- if isatty
returns 0 并且 errno
设置为 EBADF
,文件描述符未被使用,然后应该从 /dev/null
:
for (int fd = 0; fd <= 2; fd++) {
errno = 0;
if (! isatty(fd) && errno == EBADF) {
open("/dev/null", O_RDWR);
}
}
另请注意,那些未打开的流的状态根本不符合标准。 C11 7.21.3p7:
7 At program startup, three text streams are predefined and need not be opened explicitly -- standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). As initially opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.
这可以被认为是 C 启动例程中的一个失败 - 在我看来,它应该至少 /dev/null
打开这些流
虽然现在我尝试了这个,但我得出的结论是 运行 关闭标准流的程序不仅脑损伤而且完全脑死亡,因为任何 fopen
也会打开 stdin
、stdout
或 stderr
,所以我将代码修改为:
struct stat statbuf;
for (int fd = 0; fd <= 2; fd++) {
if (fstat(fd) == 0 && errno == EBADF) {
fprintf(stderr, "Id10t error: closed standard IO descriptor %d\n", fd);
abort();
}
}