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/