MinGW/MSYS
LMMSのコンパイルを試していて気が付いたりわかったりした、MinGW/MSYS環境で一般的なこと。
MinGW環境の設定
Windowsの環境変数HOMEが設定されていると、msys(sh.exe)起動時にHOMEディレクトリもソコに設定される。以下のファイルが作成される。
- .bash_history
- .inputrc
環境変数HOMEがない場合は、msysのルートに/home/(ユーザー名)ディレクトリ作成されて、上記ファイルが作成される。
EOF
久々に Windows10 + MinGW でCプログラミングしてEOFではまった。
標準入力からバイト単位読み込んで和を取ってチェックサム計算するつもりで次のようなコードを書いた。
checksum.c
標準入力からバイト単位読み込んで和を取ってチェックサム計算するつもりで次のようなコードを書いた。
checksum.c
#include <stdio.h> void main() { unsigned int sum = 0; int c; while ((c = getchar()) != EOF) { // 0x1Aを読んでも-1(EOF)を返す(Windows10+MinGW) sum += c; } printf("%8x\n", sum); }
はじめ、十分大きなファイルなら8桁16進数(4バイト)で結果が返るはずと思っていたが、どうも5桁以上にならない、
cat file1 file1 file1 | checksum
みたいにしてもsum値が変わらない、何でかと思ったら、ファイル途中にある0x1aで処理が終了していた、という話。
なお、Linux上でなら同じソースコードでも0x1aはキャラクタとして処理される。
EOF=0x1aがDOS系のテキストファイルの約束事でCP/Mが起源ということも含めて完全に忘れていた。
でもgetchar()が0x1aをEOFとして扱うかどうかはどこかで制御できそうに思える。#pragmaかな。ググったら以下のようだ。
なお、Linux上でなら同じソースコードでも0x1aはキャラクタとして処理される。
EOF=0x1aがDOS系のテキストファイルの約束事でCP/Mが起源ということも含めて完全に忘れていた。
でもgetchar()が0x1aをEOFとして扱うかどうかはどこかで制御できそうに思える。#pragmaかな。ググったら以下のようだ。
#include <stdio.h> #include <fcntl.h> #include <io.h> void main() { unsigned int sum = 0; int c; int mode; // 標準入力をバイナリモードへ変更(Visual Studio), fcntl.h, io.h mode = _setmode( _fileno( stdin ), _O_BINARY ); while ((c = getchar()) != EOF) { sum += c; } printf("%8x\n", sum); // プログラムが終了するので関係ないが、戻しておく。 _setmode( _fileno( stdin ), mode ); }
DOS環境ではファイルオープンの時にバイナリモードで開けば0x1AがEOFではなくなる。逆に、テキストモードではEOF(0x1a)と改行(0x0d,0x0a)が変換されてしまうようだ。