30

I've been trying to figure out the best way to write binary data to stdout from a C program. It works fine on Linux, but I'm having issues when I compile on Windows because "\n" gets converted to "\r\n".

Is there a standard way to write to stdout in some sort of binary mode which avoids newline conversion? If not, what is the simplest way to get Windows to stop doing this?

I'm using GCC and MinGW, and writing to stdout using fwrite.

jncraton
  • 9,022
  • 3
  • 34
  • 49

2 Answers2

35

You can use setmode(fileno(stdout), O_BINARY)

Wrap it in an ifdef if you want to keep it compatible with Linux.

See also: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setmode?view=vs-2017

Tustin2121
  • 2,058
  • 2
  • 25
  • 38
Joni
  • 108,737
  • 14
  • 143
  • 193
  • 3
    `freopen(NULL, "wb", stdout)` can also be used, and is portable C. However, it may have unwanted truncation effects; see the Application Usage section of http://pubs.opengroup.org/onlinepubs/9699919799/functions/freopen.html. For what it's worth, I think this text is wrong; when the new filename is NULL, there is no underlying `open` operation and thus the text about `O_TRUNC` does not apply. – R.. GitHub STOP HELPING ICE Jun 03 '13 at 03:15
  • 1
    @R.. you cant use `freopen` with a `NULL` filename in Windows, it will call the invalid parameter handler according to this: http://msdn.microsoft.com/en-us/library/wk2h68td.aspx and the default behavior of the invalid parameter handler is to crash the application. – Vargas Sep 10 '14 at 18:53
  • 2
    @Vargas: `NULL` is not an invalid parameter to `freopen`, so I would say that's a bug in MSVCRT... – R.. GitHub STOP HELPING ICE Sep 10 '14 at 20:19
  • 1
    The link you posted states that is implementation-defined to allow streams to be reopened. My original point is that this is not a portable way to set the stream mode to binary. – Vargas Sep 10 '14 at 21:15
  • or if "fileno" doesn't work -> raw values: stdin:0, stdout:1, stderr:2 due to MSDN documentation. – 18C Aug 27 '17 at 19:43
  • The documentation link no longer exists, here is the new link: https://msdn.microsoft.com/en-us/library/tw4k6df8.aspx -- it's a documentation page for the `_setmode` function. – antonone Jun 13 '18 at 04:17
  • Out of personal experience let me add: Only run such programs on the windows command line, NOT in PowerShell as that one keeps mangling those characters – ray_ray_ray Aug 21 '22 at 09:23
  • Can someone please rewrite this answer with an actual code snippet that's portable? – einpoklum Dec 18 '22 at 16:10
9

You can do something like that (which is sort of cross platform):

FILE *const in = fdopen(dup(fileno(stdin)), "rb");
FILE *const out = fdopen(dup(fileno(stdout)), "wb");
/* ... */
fclose(in);
fclose(out);

Or you can use write() and read() system calls directly with fileno(stdin) and fileno(stdout). Those system calls operate on lower level and don't do any conversions. But they also don't have buffering that you get from FILE streams.

wonder.mice
  • 7,227
  • 3
  • 36
  • 39