安定のWikipediaさんに納得の回答が。
プログラミングにおける改行コード
ポータブルなプログラムを記述するために、プログラミング言語は異なる改行コードを扱うためにある程度の抽象性を提供している。
C言語では'\n'(改行)、'\r'(復帰)の二つのエスケープシーケンスを提供している。言語処理系はこれらのエスケープシーケンスをそれぞれ異なった環境依存のchar型に収まる範囲の数字(例えばUNIXやWindows上の一般的な処理系においては、それぞれ、0x0A、0x0D)に変換する。
ただし、よく使われる出力関数のprintf、puts、入力関数のfgetsなどでは、'\n'に相当する数値(上記の例では0x0A)は特殊な値として処理される。これらの出力関数ではテキストモードで開かれたファイルにデータを出力する時、'\n'の部分がシステムで使用されている改行コード列に変換された文字列がファイルに出力される。例えば、UNIXでは、改行コード列は「0x0A」であり、Windowsでは「0x0D 0x0A」、Macintoshでは「0x0D」である。また、入力関数fgetsはテキストモードで開かれたファイルからデータを読み込む場合、ファイル中にシステム依存の改行コード列があれば、その部分を'\n'に対応する数値に変換したものを変数に格納する。ファイルがバイナリモードで開かれている場合には、どの入出力関数も数値を変換をせずそのままの値として読み書きする。
これらの関数は、「0x0D 0x0A」の使用を要求する通信プロトコルを使ってテキストをやりとりする場合に問題になる。そのようなストリームに対し、printf関数などを使い'\n'を出力すると、Windowsシステムにおいては期待通り「0x0D 0x0A」が送信されるが、UNIXにおいては「0x0A」しか送信されないため、問題となる。解決策として、バイナリモードを使って目的の数値(0x0D 0x0A)を直接送るとどのような場合も正しく動作する。
Java言語でも'\n'(改行)、'\r'(復帰)の二つのエスケープシーケンスを提供している。言語処理系はこれらのエスケープシーケンスを、それぞれ、16ビットの数値0x000A、0x000Dに変換する。(Java言語の char型 は16ビットUTF-16である。)
よく使われるjava.io.PrintStreamクラスのprintメソッドやprintlnメソッド、printfメソッドは、C言語の printf 関数とは異なり、これらの数値を特別扱いせず、環境依存の改行コードに変換しない。ただし、printfメソッドで使われる書式文字列中では「改行」を表現するための特殊な表記として「%n」を使える。printfメソッドはこの部分を実行環境依存の改行コードに置換した文字列を出力する。また、いずれのメソッドでも、出力されるバイト数、バイト順については設定された文字符号化方式に依存する。
つまりバイナリモードで開いていたらLF固定で、テキストモードの場合は環境などによってCRLFまたはLFになるという話。でいいのかな。
どのコンパイラとOSの組み合わせがどうなるかまでは知らない。