さて、これが私が見つけたものです。
実際、I / Oは、最終的にはネイティブのシステムコールと関数によって実行されます。
ここで、MicrosoftWindowsを例にとってみましょう。STDIN
、などの実際に使用可能なハンドルがありますSTDIO
(ここを参照)。したがって、基本的に、C ++iostream
とCはどちらもstdio
ネイティブシステム関数を呼び出しますが、C++iostream
はCのI/O関数をラップしません(最新の実装では)。ネイティブシステムメソッドを直接呼び出します。
また、私はこれを見つけました:
stdin、stdout、およびstderrがリダイレクトされると、printf()やgets()などの標準C関数を変更せずに使用して、Win32コンソールと通信できます。しかし、C ++ I / Oストリームはどうですか?cin、cout、cerr、およびclogは、Cのstdin、stdout、およびstderrと密接に関連しているため、同様に動作することが期待されます。これは半分正しいです。
C ++ I / Oストリームには、実際にはテンプレートと非テンプレートの2つの種類があります。古い非テンプレートバージョンのI/Oストリームは、標準テンプレートライブラリ(STL)によって最初に定義され、現在ANSIC++標準に吸収されている新しいテンプレートスタイルのストリームに徐々に置き換えられています。Visual C ++ v5は両方のタイプを提供し、異なるヘッダーファイルをインクルードすることで2つから選択できます。STL I / Oストリームは、新しくリダイレクトされたstdioハンドルを自動的に使用して、期待どおりに機能します。ただし、非テンプレートI/Oストリームは期待どおりに機能しません。その理由を見つけるために、Visual C++CD-ROMで便利に提供されているソースコードを調べました。
問題は、古いI / OストリームがUNIXスタイルの「ファイル記述子」を使用するように設計されていることです。ハンドルの代わりに整数が使用されます(stdinの場合は0、stdoutの場合は1など)。これはUNIX実装には便利ですが、Win32は互換性のある関数のセットを提供しないため、Win32CコンパイラはそのスタイルのI/Oを表すためにさらに別のI/O層を提供する必要があります。いずれの場合も、_open_osfhandle()を呼び出して新しいWin32ハンドルを(たとえば)stdoutに関連付けると、I/Oコードの他の層には影響しません。したがって、ファイル記述子1は、以前と同じ基になるWin32ハンドルを引き続き使用し、出力をcoutに送信しても目的の効果は得られません。
幸い、元のI / Oストリームパッケージの設計者はこの問題を予見し、クリーンで有用なソリューションを提供しました。基本クラスiosは、静的関数sync_with_stdio()を提供します。これにより、ライブラリは、標準I / Oレイヤーでの変更を反映するために、基になるファイル記述子を変更します。これはSTLI/ Oストリームに厳密に必要というわけではありませんが、害はなく、新しい形式または古い形式のI/Oストリームのいずれかで正しく機能するコードを記述できます。
(ソース)
したがって、呼び出すとsync_with_stdio()
、基になるファイル記述子が実際に変更されます。実際、古いC ++ I / Oと、整数の代わりにハンドルを使用するWindows-32などのシステムとの互換性を確保するために、設計者によって追加されました。
sync_with_stdio()
最新のC++テンプレートベースのSTLI/ Oでは、使用する必要がないことに注意してください。