「C言語のgetchar関数の戻り値がcharではなくintになってるのは、EOFを返すから。」
「で、EOFはマクロで-1と定義されてるから、charの0〜255に収まらないため、戻り値をintにしてある。」

とかいうのは、c言語の入門サイトによく書いてあるが、どうもよく分かりません。

というのは、EOFというのは、DOS(Windows?)では、0x1aに割り当てられてるので、なんで「0〜255に収まらない」んでしょうかねえ。

「0x1a=EOF」が書いてあるサイト

http://www9.plala.or.jp/sgwr-t/c/sec17.html

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=32351&forum=7&7

だいたい、asciiコードで、0x1aは、「SU」または、「SUB」というものに割り当てられているんですが。

asciiコード表

(余談だが、制御コードについてどうやらタイプライタやテレタイプの時代の遺物が今でも残ってるようだ。)

と思っていたら、このようなのを見つけたので、とりあえず読んでみよう・・・。
EOFが理解できない
EOFが理解できない(どこかの掲示板)

参考サイトに書いてあるところによると、
getcharとかの戻り値であるEOFと、文字コード0x1aで表されるEOFは別物
だそうだ。

以下引用

56 名前: トリッキーの1 投稿日: 2001/03/07(水) 05:33

>>55 EOFという文字コードは0x1Aなので、
「MS-DOSファイルのEOFコードは1Ahである」
は間違いじゃ無いでしょうね。英語もほぼ同じ事を言っています。
ここでいうEOFコードというのは、「ここがファイルの終わりだよ」と
作成者が親切に?付けるものなので、その気になれば1つのファイルに
EOFコードをたくさん書くことも可能です。

しかし、標準ライブラリ関数が返すEOF(-1)は、
「ファイルの終わりまで読んだよ」という意味です。
テキストモードで開いた場合、0x1Aを読むとfgetc()などはEOFを返しますが、
バイナリモードで開いた場合、ファイルの本当の最後に行き当たって初めてEOFが返ります。

全く同じ"EOF"という文字で表されるので非常にわかりにくいのですが、
プログラム上で使用するEOFと、ファイルの中にあるEOFコードとは
別物であり、定義が違う事に注意しましょう。

なんかまともに書いてしまった。
テキストモード云々のあたりに自信がないので、
間違ったことがあれば誰か訂正してください。

大変分かりやすい説明だが、つまり、テキストモードでファイルを開いたときに、文字コード0x1aを見つけると、getcharは0x1aではなくEOF(=-1)を返す、という関係のようだ。バイナリモードなら無関係で、ファイルの終わりに来たときのみEOFを返すそうだ。

気持ちとしては、getcharが、「ここはファイルの終わりだよ〜」ってことを知らせるために、「わざわざ」EOFを返してくれている感じだ。

これを確かめるために、次のようなプログラムを作ってみた。


#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int main(void)
{
	FILE *fp;
	int c;
	fp = fopen("eof_test.txt","r");

	for(;;){
		c = fgetc(fp);
		printf("%02x\n",c);
		if(c == EOF)
		  break;
	}
	return 0;
}


で、eof_test.txtは、
abcdefg
という感じ。

これをエディタで表示したときに、最後に「EOF」と表示されるが、これもエディタがファイルの終わりをわざわざ教えてくれているわけで、文字コードとは関係ない。 これをborlandのコンパイラでコンパイルして、XP上で実行してみると、

61
62
63
64
65
66
67
ffffffff
と表示されて、確かに最後に0xffffffff(=-1)が表示された。
次に、バイナリエディタで、eof_test.txtのcの部分を、1aに書き換えてやる。
すると、テキストエディタ上では、
abc^Zefg
と表示された。^Zと表示されるものが0x1aに相当するらしい。(Windowsではcontrol-Zで制御コード0x1aを入力できるから。)
で、さっきのプログラムを実行してみると、
61
62
63
ffffffff
となる。0x1aが-1に変換されて出力された。
一方、さっきのコードをcygwin上のgccでコンパイルして実行すると、
61
62
63
1a
65
66
67
ffffffff
となる。linuxではファイルオープン時にバイナリモードとテキストモードの区別をしないため、0x1aはEOFとはみなされず、本当にファイルの最後でだけ-1が出力されるのであろう。

というわけで、まとめ

  • 文字コード0x1aとgetcharなどで返されるEOFは全く別物
  • ファイルの最後に0x1aなる文字があるわけではない。(昔はそういう仕様のファイルシステムがあったようだが、DOSでは無くても可。)
  • 0x1aまたはファイルの最後を発見すると、getchar関数は気を効かして、そこをファイルの最後とみなしてEOF(=-1)を返してくれる。ただし、バイナリモードやlinux上では0x1aをファイルの最後とみなさず、本当にファイルの最後でしかEOFを返さない。
ふー、疲れた。