標準入出力のバイナリモード †例えば K&R のプログラミング言語 C 第2版 の 1.5.2 の例題の文字数のカウントを Windows でやると <CR><LF> の対で1文字とカウント される。つまりファイルを redirect してやると、 ファイルのバイト数とカウント数が一般には一致しない。 標準出力も同様で '\n' 一文字を出力すると、<CR><LF> の対が出力される。 これは Windows では、標準入出力が default で テキストモードであるためである。これはこれで 便利なこともあるが、バイナリモードで行いたいことも ある。 ファイル入出力なら open 時に指定できるが、、 †C でも C++ でもファイル入出力に関しては規格上 open 時に モードを設定することができるので、 これを使えばよいが、標準入出力はプログラムの最初から すでに open されており、ファイルとして実装されて いる保障も無い。更にモード変更の仕組みも用意されて いない。 というわけで処理系依存にならざるを得ない。 gcc と VC 共通コード †一応、gcc/g++ (mingw 3.4.5) と Visual C++ 9.0 Express Edition と共通のコードが書けたので、メモしておく。 以下は、K&R の 1.5.2 の文字数をカウントする例題を Windows バイナリ化したものである。 #include <iostream> #include <cstdio> #include <fcntl.h> #include <io.h> int main() { std::ios_base::sync_with_stdio(false); _setmode(_fileno(stdin),_O_BINARY); std::ios_base::sync_with_stdio(true); long nc = 0; char c; while(std::cin.get(c)) ++nc; std::cout << nc << std::endl; return 0; } sync_with_stdio について †ここで、sync_with_stdio は ios_base の静的公開関数で あるので、これを継承している ios でも istream でも ostream でも、あるいはそのオブジェクトである cin や cout からでも呼び出せる。例えば std::ios::sync_with_stdio(false); _setmode(_fileno(stdin),_O_BINARY); std::ios::sync_with_stdio(true); としてもよいし、 std::cin.sync_with_stdio(false); _setmode(_fileno(stdin),_O_BINARY); std::cin.sync_with_stdio(true); としてもよい。ただし、sync_with_stdio はこの関数一回の 呼び出しですべての標準入出力に影響を与えるが、 一番最後の書き方は、このことが見えにくくなるので、 あまり薦めない。 |