在win32下对stdin使用fread()的问题

jba*_*ter 3 c windows pipe stdio

我试图在Win32下以二进制模式解析stdin中的数据.我的代码所做的第一件事就是在开头检查一个4byte的头:

int riff_header;
fread(&riff_header, sizeof(riff_header), 1, ifp);
//  'RIFF' = little-endian
if (riff_header != 0x46464952) {
    fprintf(stderr, "wav2msu: Incorrect header: Invalid format or endianness\n");
    fprintf(stderr, "         Value was: 0x%x\n", riff_header);
    return -1;
}
Run Code Online (Sandbox Code Playgroud)

stdin 在读取之前已经切换到二进制模式:

if (*argv[argc-1] == '-') {
    fprintf(stderr, "Reading from stdin.\n");
    infile = stdin;
    // We need to switch stdin to binary mode, or else we run
    // into problems under Windows
    freopen(NULL, "rb", stdin);
}
Run Code Online (Sandbox Code Playgroud)

这段代码在Linux下工作正常,但是在Win32(特别是Windows XP)上,fread似乎只能读取单个字节,从而导致评估失败.例:

> ffmeg.exe -i ..\test.mp3 -f wav pipe:1 2> nul |..\foo.exe -o test.bin -
Reading from stdin.
foo: Incorrect header: Invalid format or endianness
     Value was: 0x4
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Gio*_*gio 5

http://pubs.opengroup.org/onlinepubs/009695399/functions/freopen.html,我发现了以下内容:

如果filename是空指针,则freopen()函数将尝试将流的模式更改为mode指定的模式,就好像当前与该流关联的文件的名称已被使用一样.在这种情况下,如果对freopen()的调用成功,则不需要关闭与流关​​联的文件描述符.它是实现定义的,允许更改模式(如果有),以及在什么情况下.

也许您应该检查您正在使用的编译器和库是否允许更改模式(从文本到二进制).你使用的是哪个编译器?

更新/摘要

使用MinGW,您可以调用setmode()来切换stdin流的模式.您应该将模式设置为_O_BINARY,它在fcntl.h中定义.有关更多信息,请参阅http://gnuwin32.sourceforge.net/compile.html


Ada*_*eld 5

按照MSDN文档,它不允许通过NULLpath参数freopen,所以调用freopen几乎可以肯定是失败的; 你检查了返回值和值errno吗?C89没有规定的行为freopenpathNULL; C99可以,但Microsoft C运行时不符合(并且声称不符合)C99.

如果您确实需要从中读取二进制信息stdin,则可能必须使用特定于平台的代码并直接ReadFile在文件上读取原始二进制数据GetStdHandle(STD_INPUT_HANDLE).

  • 或者`setmode(fileno(stdin),O_BINARY);`[MSDN](http://msdn.microsoft.com/en-us/library/tw4k6df8 \(v = vs.80 \).aspx) (9认同)