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

时间:2011-08-13 19:54:42

标签: c windows pipe stdio

我正在尝试在Win32下以二进制模式解析stdin中的数据。 我的代码所做的第一件事是在开头检查一个4字节的标题:

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;
}
在阅读之前,

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);
}

此代码在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

我做错了什么?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:5)

根据MSDN documentation,不允许NULL传递path的{​​{1}}参数,因此对freopen的调用几乎肯定会失败;你检查了freopen的返回值和值吗? errnofreopen时,C89未指定path的行为; C99可以,但Microsoft C运行时不符合(并且声称不符合)C99。

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