检查FILE *是否为stdout;便携式?

时间:2018-06-14 19:19:01

标签: c stdout portability

我目前正在编写一段代码,其用途如下:

program input.txt output.txt

program input.txt

在这种情况下,它默认为stdout

这是我现在的代码(在main()内):

FILE *outFile;
if (argc < 3) {
        outFile = stdout;
    } else {
        fprintf(stdout, "Will output to file %s\n", argv[2]);
        outFile = fopen(argv[2], "w");
        if (outFile == NULL) {
            fprintf(stderr, "ERR: Could not open file %s. Defaulting to stdout\n", argv[2]);
            outFile = stdout;
        }
    }
/* ... write stuff to outFile... */
if (argc < 3 && outFile != stdout) {
        fclose(outFile);
    }

这些是我的担忧:首先,这将成功打开和关闭文件提供时?此外,这会成功关闭标准输出?如果我关闭stdout,会发生什么不好的事吗?

另外,这是便携式吗?我使用gcc进行编译,但该项目将由一位使用Windows的教授进行评估。

道歉,如果这是一个混乱的问题。我来自Python并且不是CS专业(我正在学习数学)。

3 个答案:

答案 0 :(得分:2)

是的,它是便携式的,没关系。

答案 1 :(得分:2)

是的,它是便携式的。您已分配 export default MainNavigation = createBottomTabNavigator( { Profile:{ screen: Profile, navigationOptions: ({ navigation }) => ({ tabBarIcon: ({ focused, tintColor }) => { return <Image source={require('./images/tab_explore.png')} /> } }), } }, { tabBarComponent: props =>{ return( <View style={{backgroundColor:"black"}}> <Image style={{ width:'100%', height: 80 }} source={ require('./images/bottom_btn.png')} /> </View> ); } }) ,因此只要您不在计划的其他位置重新分配其中任何一个,它们就会相等。

你也不需要outfile = stdout测试 - 这两个条件应该总是相同的,因为你只有在那个时才进行分配。

答案 2 :(得分:1)

在任何将重要数据写入stdout的程序中,应该在退出之前关闭stdout,以便您可以检查并报告延迟的写入错误。 (延迟写入错误是一个设计错误; fcloseclose失败应该是不可能的。但我们仍然坚持使用它们。)

通常的构造是在main的最后,

if (ferror(stdout) || fclose(stdout)) {
    perror("stdout: write error");
    return 1;
}
return 0;

某些程序也会在fflush中添加fclose,但ISO C要求fflush执行stdout,因此不应该 。这个结构完全是便携式的。

在退出之前,这是你做的最后一件事,这一点非常重要。图书馆假设stdout永远不会关闭是相对常见的,因此如果您在关闭stdin后调用它们,它们可能会出现故障。 stderrstdout也很麻烦,但我还没有遇到一个想要来关闭它们的情况。

有时候您希望在程序完成之前关闭FILE。在这种情况下,您实际上应该保持int rfd = open("/dev/null", O_WRONLY); if (rfd == -1) perror_exit("/dev/null"); if (fflush(stdout) || close(1)) perror_exit("stdout: write error"); dup2(rfd, 1); close(rfd); 打开但关闭基础&#34;文件描述符&#34;并用假人替换它。

open

此构造不可移植到Windows。有一个等价物,但我不知道它是什么。它也不是线程安全的:另一个线程可以在closedup2操作之间调用stdout并分配fd 1,或者它可以尝试写一些东西给{ {1}}在该窗口中出现虚假写入错误。为了线程安全,你必须复制旧的fd 1并通过该句柄关闭它:

// These allocate new fds, which can always fail, e.g. because
// the program already has too many files open.
int new_stdout = open("/dev/null", O_WRONLY);
if (new_stdout == -1) perror_exit("/dev/null");
int old_stdout = dup(1);
if (old_stdout == -1) perror_exit("dup(1)");

flockfile(stdout);
if (fflush(stdout)) perror_exit("stdout: write error");
dup2 (new_stdout, 1); // cannot fail, atomically replaces fd 1
funlockfile(stdout);

// this close may receive delayed write errors from previous writes
// to stdout
if (close (old_stdout)) perror_exit("stdout: write error");

// this close cannot fail, because it only drops an alternative
// reference to the open file description now installed as fd 1
close (new_stdout);

操作顺序至关重要:opendupfflush来电必须在dup2来电之前进行,close来电必须在必须在dup2来电之前锁定fflush来调用stdout,直到dup2来电之后。

其他可能的并发症,作为一项练习处理:

  • 当您不想在错误时停止整个程序时,清理临时fds并锁定错误
  • 如果线程可能在操作中被取消
  • 如果并发线程可能会调用forkexecve mid-operation