It's been an unpleasant surprise that '\n'
is replaced with "\r\n"
on Windows, I did not know that. (I am guessing it is also replaced on Mac...)
Is there an easy way to ensure that Linux, Mac and Windows users can easily exchange text files?
By easy way I mean: without writing the file in binary mode or testing and replacing the end-of-line chars myself (or with some third party program/code). This issue effects my C++ program doing the text file I/O.
The default value on both Windows and Mac Classic clients is crlf .
CR = Carriage Return ( \r , 0x0D in hexadecimal, 13 in decimal) — moves the cursor to the beginning of the line without advancing to the next line. LF = Line Feed ( \n , 0x0A in hexadecimal, 10 in decimal) — moves the cursor down to the next line without returning to the beginning of the line.
The newline character ( \n ) is called an escape sequence, and it forces the cursor to change its position to the beginning of the next line on the screen. This results in a new line.
For example, in Linux a new line is denoted by “\n”, also called a Line Feed. In Windows, a new line is denoted using “\r\n”, sometimes called a Carriage Return and Line Feed, or CRLF. Adding a new line in Java is as simple as including “\n” , “\r”, or “\r\n” at the end of our string.
Apologies for the partial overlap with other answers, but for the sake of completeness:
Myth: endl
is 'more portable' since it writes the line ending depending on the platform convention.
Truth: endl
is defined to write \n
to the stream and then call flush
. So in fact you almost never want to use it. All \n
that are written to a text-mode stream are implicitly converted to \r\n
by the CRT behind the scenes, whether you use os<<endl
, os<<'\n'
, or fputs("\n",file)
.
Myth: You should open files in text mode to write text and in binary mode to write binary data.
Truth: Text mode exists in the first place because some time ago there were file-systems that distinguished between text files and binary files. It's no longer true on any sane platform I know. You can write text to binary-opened files just as well, you just loose the automatic \n
-> \r\n
conversion on Windows. However, this conversion causes more harm than good. Among others, it makes your code behave differently on different platforms, and tell/seek
become problematic to use. Therefore it's best to avoid this automatic conversion. Note that POSIX does not distinguish between binary and text mode.
How to do text: Open everything in binary mode and use the plain-old \n
. You'll also need to worry about the encoding. Standardize on UTF-8 for Unicode-correctness. Use UTF-8 encoded narrow-strings internally, instead of wchar_t
which is different on different platforms. Your code will become easier to port.
Tip: You can force MSVC to open all files in binary mode by default. It should work as follows:
#include <stdio.h>
#include <iostream>
int main() {
_fmode = _O_BINARY;
std::ofstream f("a.txt"); // opens in binary mode
}
EDIT: As of 2021, Windows 10 Notepad understands UNIX line endings.
The issue isn’t with endl
at all, it’s that text streams reformat line breaks depending on the system’s standard.
If you don’t want that, simply don’t use text streams – use binary streams. That is, open your files with the ios::binary
flag.
That said, if the only issue is that users can exchange files, I wouldn’t bother with the output mode at all, I’d rather make sure that your program can read different formats without choking. That is, it should accept different line endings.
This is by the way what any decent text editor does (but then again, the default notepad.exe
on Windows is not a decent text editor, and won’t correctly handle Unix line breaks).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With