c++のeofは事後確認

cppC++でfstreamを使ってファイルアクセスをしたとき、eofの動きがCのFileライブラリとかの動きと違うことに気がついた。Cの場合は「読む前にもうデータがないことがわかる」が、C++のstreamの場合は「読んでみて初めてデータがないことがわかる」である。
#include <iostream>
#include <string>
#include <fstream>

using namespace std;

int main(void)
{
        ifstream ifs("test.txt");
        char c;

        while (!ifs.eof()) {
                c = ifs.get();
                cout << hex << (int)c << endl;
        }

        return 0;
}
を動かすと、
$ cat test.txt
abc
$ ./test
61
62
63
a
ffffffff
$
とよけいなfffffff(元はcharの0xff)がつく。最後の改行(LF=0x0a)を読んだあとeof()はtrueにならないのである。データがない状態でgetやreadをして、ないことがわかるとやっとeof()がtrueになるのである。さきほどのプログラムを期待通りに動かすには、読む前にeofチェックではなく、読んだ後にチェックすべきである。
#include <iostream>
#include <string>
#include <fstream>

using namespace std;

int main(void)
{
        ifstream ifs("test.txt");
        char c;

        for(;;) {
                c = ifs.get();
                if (ifs.eof()) {
                        break;
                }
                cout << hex << (int)c << endl;
        }

        return 0;
}
これは最初に確認したのはVisual C++だが、cygwin上のgppでも同じ動きだったので多分linux上のgppもいっしょ。いまさら周知の事実なんだろうが、今頃気が付いたのでメモ。