Jam*_* Ko 2 c windows io stdio fread
TL; DR:为什么freopen(NULL, "rb", stdin)在Windows 上总是失败?
我正在尝试base64在C中重新实现一个从stdin获取输入并将编码的等价物输出到stdout的编码器.我之前的帖子中有一个问题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;
}
本质上,它从stdin读取数据fread,编码到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的源代码,看起来他们正在使用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?如果相关,我在Windows上使用MinGW-w64和GCC.
freopen()一般会失败C标准说:
如果
filename是空指针,则该freopen函数尝试将stream指定的模式更改为指定的模式mode,就好像当前与该流关联的文件的名称已被使用一样.它是实现定义的,允许更改模式(如果有),以及在什么情况下.
据推测,您的实施不允许您尝试进行更改.例如,在Mac OS X上,freopen()添加的手册页:
新模式必须与最初打开流的模式兼容:
- 最初以模式"r"打开的流只能使用相同的模式重新打开.
- 最初以模式"a"打开的流可以使用相同的模式或模式"w"重新打开.
- 最初以模式"w"打开的流可以使用相同的模式或模式"a"重新打开.
- 最初以模式"r +","w +"或"a +"打开的流可以使用任何模式重新打开.
话虽如此,在Mac OS X上(b无论如何都是无操作),你会没事的.
freopen()在Windows上失败?但是,你在Windows上.您需要学习如何查找和阅读文档.对于我正在寻找的任何功能,我使用术语"site:msdn.microsoft.com freopen"的谷歌搜索.该特定搜索产生了说明的手册freopen():
如果
path,mode或者stream是空指针,或者如果filename是空字符串,则这些函数将调用无效参数处理程序,如参数验证中所述.如果允许继续执行,则这些函数将errno设置为EINVAL并返回NULL.
这是记录在案的行为:它也是您所看到的行为.系统手册很有帮助.它基本上说"你不应该".
我注意到,在我回答你刚才的问题,我指着_setmode():
但是,您更有可能需要
_setmode():Run Code Online (Sandbox Code Playgroud)_setmode(_fileno(stdin), O_BINARY);
这是在答案,给出的建议问题是deamentiaemundi指出.
我顺便提一下,微软的手册页setmode()说:
不推荐使用此POSIX函数.请改用符合ISO C++标准
_setmode.
这是一个好奇的评论,因为POSIX首先没有标准化函数setmode().
您可以找到Microsoft的文档fileno().它也有关于POSIX的spiel(但这次它是准确的; POSIX确实指定fileno())并引用你_fileno().
| 归档时间: | 
 | 
| 查看次数: | 631 次 | 
| 最近记录: |