binary output to stdout in Windows

J

John Forkosh

I have a C program that writes binary output to stdout,
which works fine in Unix/Linux. But when someone else
compiled and ran it in Windows, every time the program
emitted a 0x0A, Windows interpreted it as an lf, and
preceded it with a spurious 0x0D cr. Cute. Is there
some way I can freopen() (so to speak) stdout in binary
mode under Windows so that doesn't happen? Hopefully,
the fix would be portable, so it could compile and
execute under Unix, too, with no ill effects.
Thanks,
 
C

Chris Torek

I have a C program that writes binary output to stdout,
which works fine in Unix/Linux. But when someone else
compiled and ran it in Windows, every time the program
emitted a 0x0A, Windows interpreted it as an lf, and
preceded it with a spurious 0x0D cr. Cute. Is there
some way I can freopen() (so to speak) stdout in binary
mode under Windows so that doesn't happen? Hopefully,
the fix would be portable, so it could compile and
execute under Unix, too, with no ill effects.

In C99 there is a way (I think -- it is not in my draft; I should
probably buy the actual C99 .pdf file):

FILE *result;
...
result = freopen(NULL, "wb", stdout);

Here, "result" should compare equal to stdout on success, and NULL
on failure.

Unfortunately, passing NULL to freopen() in C89 results in undefined
behavior -- and in many real implementations, a crash and/or
core-dump.

You might use the theoretically-portable freopen() method as your
"standard" technique that is rarely used today but more frequently
tomorrow, and meanwhile resort to some nonstandard method(s) for
existing implementations. (I have no idea what those might be
beyond something spelled something like "setmode".)
 
I

Irrwahn Grausewitz

Chris Torek said:
In C99 there is a way (I think -- it is not in my draft; I should
probably buy the actual C99 .pdf file):

FILE *result;
...
result = freopen(NULL, "wb", stdout);

Here, "result" should compare equal to stdout on success, and NULL
on failure.

Unfortunately, passing NULL to freopen() in C89 results in undefined
behavior -- and in many real implementations, a crash and/or
core-dump.

Unfortunately, even in C99 this is not as portable as
one might think (or wish):

C99 7.19.5.4#3:
---------------
If filename is a null pointer, the freopen function
attempts 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.
It is implementation-defined which changes of mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
are permitted (if any), and under what circumstances.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

FWIW, on at least one popular platform this C99 program:

#include <stdio.h>
int main( void )
{
FILE *fp = freopen( NULL, "wb", stdout );
fputs( fp ? "Ok.\n" : "Dang!\n", stderr );
return 0;
}

prints 'Dang!' and leaves stdout closed! :-(

Conclusion: the only portable way (I can think of)
to write binary data from a C program is writing it
to a file explicitly fopen()ed in "[w|a][+]b" mode.

<snip>

Regards
 
T

Toni Uusitalo

You might use the theoretically-portable freopen() method as your
"standard" technique that is rarely used today but more frequently
tomorrow, and meanwhile resort to some nonstandard method(s) for
existing implementations. (I have no idea what those might be
beyond something spelled something like "setmode".)
--

I didn't know freopen could be used to change file mode in the newer
standard.
But I guess this doesn't help the OP in the present time. Luckily all
programmers
love to write tons of #ifdefs ;-)

I'll use "theoretically-portable" phrase next to "theoretical performance"
numbers next time I advertise some piece of s**tware I've written ;-)

with respect,
Toni Uusitalo
 
J

John Forkosh

: "John Forkosh" wrote:
: > I have a C program that writes binary output to stdout,
: > which works fine in Unix/Linux. But when someone else
: > compiled and ran it in Windows, every time the program
: > emitted a 0x0A, Windows interpreted it as an lf, and
: > preceded it with a spurious 0x0D cr. Cute. Is there
: > some way I can freopen() (so to speak) stdout in binary
: > mode under Windows so that doesn't happen? Hopefully,
: > the fix would be portable, so it could compile and
: > execute under Unix, too, with no ill effects. Thanks,

: try _setmode()
: Search _setmode (third hit) in
: http://msdn.microsoft.com/library
: --
: Toni Uusitalo

Thanks, Toni. As suggested, I modified code to include,
essentially,
if ( _setmode(_fileno(stdout), _O_BINARY)
== -1 ) ; /* error */
guarded by an ugly #ifdef to determine whether or not
it's a Windows compilation.
Mailed fix to user who replied that he hasn't had time
to try it yet, but is "sure it will work" -- poor, naive soul!
I'll post another short followup when outcome is known,
especially if my cynical, Murphy's Law attitude bears its
usual fruits.

Chris Torek wrote:
: In C99 there is a way (I think -- it is not in my draft; I should
: probably buy the actual C99 .pdf file):
: FILE *result;
: result = freopen(NULL, "wb", stdout);
: Here, "result" should compare equal to stdout on success, and NULL
: on failure. Unfortunately, passing NULL to freopen() in C89 results
: in undefined behavior -- and in many real implementations, a crash
: and/or core-dump.
: You might use the theoretically-portable freopen() method as your
: "standard" technique that is rarely used today but more frequently
: tomorrow, and meanwhile resort to some nonstandard method(s) for
: existing implementations. (I have no idea what those might be
: beyond something spelled something like "setmode".)
: --
: Chris Torek, Wind River Systems, http://web.torek.net/torek/index.html

-- and --

: Unfortunately, even in C99 this is not as portable as
: one might think (or wish):
: C99 7.19.5.4#3:
: If filename is a null pointer, the freopen function
: attempts 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.
: It is implementation-defined which changes of mode
: are permitted (if any), and under what circumstances.
: ^^^^^^^^^^^
: FWIW, on at least one popular platform this C99 program:
: #include <stdio.h>
: int main( void )
: { FILE *fp = freopen( NULL, "wb", stdout );
: fputs( fp ? "Ok.\n" : "Dang!\n", stderr );
: return 0; }
: prints 'Dang!' and leaves stdout closed! :-(
: Conclusion: the only portable way (I can think of)
: to write binary data from a C program is writing it
: to a file explicitly fopen()ed in "[w|a][+]b" mode.
: --
: Irrwahn Grausewitz ([email protected])

Thanks Chris and Irrwahn. For the time being, at least,
I used Toni's suggestion since a non-portable solution
is better than a portable non-solution.
Can't write to a file because program is used as a
cgi, and therefore has to emit bytes directly to stdout
so Apache (or whatever) can pick them up.

Thanks again for help, guys,
 
D

Dan Pop

In said:
In C99 there is a way (I think -- it is not in my draft; I should
probably buy the actual C99 .pdf file):

For this particular purpose, it is enough to upgrade to the last public
draft, N869:

[#3] If filename is a null pointer, the freopen function
attempts 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. It is implementation-defined
which changes of mode are permitted (if any), and under what
circumstances.

Dan
 
D

Dan Pop

In said:
FWIW, on at least one popular platform this C99 program:

#include <stdio.h>
int main( void )
{
FILE *fp = freopen( NULL, "wb", stdout );
fputs( fp ? "Ok.\n" : "Dang!\n", stderr );
return 0;
}

prints 'Dang!' and leaves stdout closed! :-(

If this platform doesn't claim C99-conformance, the program invokes
undefined behaviour, anyway. As Chris mentioned, this is not a C89
feature.
Conclusion: the only portable way (I can think of)
to write binary data from a C program is writing it
to a file explicitly fopen()ed in "[w|a][+]b" mode.

What is preventing a conforming implementation from having an fopen()
that fails for all these modes?

Being a QoI issue, it is reasonable to expect conforming C99
implementations to allow mode changes when freopen() is invoked this way.

Dan
 
J

John Forkosh

: : "John Forkosh" wrote:
: : > I have a C program that writes binary output to stdout,
: : > which works fine in Unix/Linux. But when someone else
: : > compiled and ran it in Windows, every time the program
: : > emitted a 0x0A, Windows interpreted it as an lf, and
: : > preceded it with a spurious 0x0D cr. Cute. Is there
: : > some way I can freopen() (so to speak) stdout in binary
: : > mode under Windows so that doesn't happen? Hopefully,
: : > the fix would be portable, so it could compile and
: : > execute under Unix, too, with no ill effects. Thanks,

: : try _setmode()
: : Search _setmode (third hit) in
: : http://msdn.microsoft.com/library
: : --
: : Toni Uusitalo

: Thanks, Toni. As suggested, I modified code to include,
: essentially,
: if ( _setmode(_fileno(stdout), _O_BINARY)
: == -1 ) ; /* error */
: guarded by an ugly #ifdef to determine whether or not
: it's a Windows compilation.
: Mailed fix to user who replied that he hasn't had time
: to try it yet, but is "sure it will work" -- poor, naive soul!
: I'll post another short followup when outcome is known,

User reports fix works exactly as intended.
Thanks again,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top