TL;博士:为什么freopen(NULL, "rb", stdin)在Windows上总是失败?

我正在尝试在C中重新实现base64编码器,该编码器从stdin接收输入并将编码后的等效输出到stdout。我遇到了一个问题in my previous post,其中fread过早发出了EOF信号。这是我的主要方法:

int main(void)
{
    unsigned char buffer[BUFFER_SIZE];
    unsigned char base64_buffer[BASE64_BUFFER];

    while (1)
    {
        TRACE_PUTS("Reading in data from stdin...");
        size_t read = fread(buffer, 1, sizeof(buffer), stdin); /* Read the data in using fread(3) */

        /* Process the buffer */

        TRACE_PRINTF("Amount read: %zu\n", read);
        TRACE_PUTS("Beginning base64 encode of buffer");
        size_t encoded = base64_encode(buffer, read, base64_buffer, sizeof(base64_buffer));

        /* Write the data to stdout */
        TRACE_PUTS("Writing data to standard output");
        ...

        if (read < sizeof(buffer))
        {
            break; /* We reached EOF or had an error during the read */
        }
    }

    if (ferror(stdin))
    {
        /* Handle errors */
        fprintf(stderr, "%s\n", "There was a problem reading from the file.");
        exit(1);
    }

    puts(""); /* Output a newline before finishing */

    return 0;
}

本质上,它使用fread从stdin读取数据,编码为base64,将其写入stdout,然后在循环结束时检查是否已到达EOF。

当我将二进制文件的内容通过管道传输到此应用程序的stdin时,它将仅读取文件中总字节的一小部分。例如:
$ cat /bin/echo | my_base64_program >/dev/null # only view the trace output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 600
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 600
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 600
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output
TRACE: C:/Users/James/Code/c/base64/main.c:23: Reading in data from stdin...
TRACE: C:/Users/James/Code/c/base64/main.c:28: Amount read: 569
TRACE: C:/Users/James/Code/c/base64/main.c:29: Beginning base64 encode of buffer
TRACE: C:/Users/James/Code/c/base64/main.c:43: Writing data to standard output

$ cat /bin/echo | wc -c
28352

如您所见,/bin/echo的长度为28352字节,但其中只有约2400个字节正在处理中。我相信原因是因为stdin未被认为是二进制文件,所以某些控制字符(如链接文章答案中提到的Control-Z)过早地发出了EOF信号。

我看了看base64 source code,看起来好像他们在使用xfreopen(这只是freopen的包装器)告诉fread将stdin解释为二进制。因此,我在进行while循环之前进行了以下操作:
if (!freopen(NULL, "rb", stdin))
{
    fprintf(stderr, "freopen failed. error: %s\n", strerror(errno));
    exit(1);
}

但是,现在我的应用始终会退出并显示以下内容:
$ cat /bin/echo | my_base64_program
freopen failed. error: Invalid argument

那么当freopen适用于base64时,为什么此时ojit_code失败了?如果相关的话,我正在Windows上使用MinGW-w64和GCC。

最佳答案

为什么freopen()通常可能会失败

C标准说:



据推测,您的实现不允许您尝试进行的更改。例如,在Mac OS X上,freopen()的手册页添加了:



话虽如此,在Mac OS X(无论如何b都是禁止操作)上,您就可以了。

为什么freopen()在Windows上专门失败

但是,您使用的是Windows。您需要学习如何查找和阅读文档。无论我要寻找什么功能,我都使用Google搜索来搜索“site:msdn.microsoft.com freopen”。特定的搜索产生了 freopen() 的手册,其中说:



这就是记录的行为:这也是您所看到的行为。系统手册对您有所帮助。它基本上说“你不可以”。

如何在Windows上修复标准输入的输入模式

我注意到在answer到您的previous question中,我指向_setmode():



这是question指向deamentiaemundi的答案中给出的建议。

顺带一提,我注意到 setmode() 的Microsoft手册页说:



这是一个奇怪的评论,因为POSIX最初并未将函数 setmode() 标准化。

您可以找到Microsoft的 fileno() 文档。它也具有有关POSIX的特点(但这次是准确的; POSIX确实指定了 fileno() )并将您引至 _fileno()

关于c - 我想将stdin解释为二进制文件。为什么freopen在Windows上失败?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39339164/

10-08 22:36