如何处理open()返回1

时间:2017-11-12 20:29:13

标签: c io file-descriptor

我编写了一个创建空文本文件的程序,如果成功则打印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有效但不是解决方案,我不能禁止我的程序用户关闭标准输出。

这是解决问题的正确方法吗?

1 个答案:

答案 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} },fopenstdin,所以我将代码修改为:

stdout