Problems using fread() on stdin under win32

2019-01-25 22:47发布

问题:

I'm trying to parse data from stdin in binary mode under Win32. The first thing my code does is to check for a 4byte header at the beginning:

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 has been switched to binary mode before reading from it:

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

This code works fine under Linux, however on Win32 (specifically Windows XP), the fread only seems to read a single byte and thus cause the evaluation to fail. Example:

> 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

What am I doing wrong?

回答1:

At http://pubs.opengroup.org/onlinepubs/009695399/functions/freopen.html I have found the following:

If filename is a null pointer, the freopen() function shall attempt to change the mode of the stream to that specified by mode, as if the name of the file currently associated with the stream had been used. In this case, the file descriptor associated with the stream need not be closed if the call to freopen() succeeds. It is implementation-defined which changes of mode are permitted (if any), and under what circumstances.

Maybe you should check if the change of mode (from text to binary) is allowed by the compiler and libraries you are using. Which compiler are you using?

Update / summary

Using MinGW you can call setmode() to switch the mode of the stdin stream. You should set the mode to _O_BINARY, which is defined in fcntl.h. For more information see e.g. http://gnuwin32.sourceforge.net/compile.html



回答2:

According to the MSDN documentation, it's not permitted to pass NULL for the path parameter of freopen, so the call to freopen is almost certainly failing; have you checked the return value and the value of errno? C89 does not specify the behavior of freopen when path is NULL; C99 does, but the Microsoft C runtime is not (and does not claim to be) C99-compliant.

If you really need to read binary info from stdin, you might have to use platform-specific code and read the raw binary data directly with ReadFile on the file GetStdHandle(STD_INPUT_HANDLE).