MinGWのfwriteがおかしい

aaaaaa

という内容のtest.txtを用意する。

同じディレクトリで以下を実行する

#include <stdio.h>

int main() {
	FILE *file;
	if ((file = fopen("test.txt", "r+")) == NULL) {
		printf("file open error.");
		return 1;
	}

	char c;
	int len = fread(&c, 1, 1, file);
	printf("read length:%d\n", len);
	printf("read char: %c\n", c);

	c = 'X';
	len = fwrite(&c, 1, 1, file);
	printf("write length:%d\n", len);

	int errno = fclose(file);
	printf("fclose errno:%d\n", errno);

	return 0;
}

するとtest.txtの中身はどうなるだろうか。

aXaaaa

になるというのが普通の感覚だろう。実際linux上のgccではそうなる。

しかしwindows上のMinGWだと

aaaaaa

のままなのだ。

fwriteが失敗した場合、戻り値が書きこもうとしたバイト数未満になるはずだがそうはなっていない。
fcloseの戻り値も0で正常だ。
MinGWだけならまだしもVisual Studio 2010 C++でも同じ挙動となる。

しかしながらプログラムを以下のように直すとうまくいく。

#include <stdio.h>

int main() {
	FILE *file;
	if ((file = fopen("test.txt", "r+")) == NULL) {
		printf("file open error.");
		return 1;
	}

	char c;
	int len = fread(&c, 1, 1, file);
	printf("read length:%d\n", len);
	printf("read char: %c\n", c);

	// 以下3行を追加。
	int pos = ftell(file);
	printf("file pos:%d\n", pos);
	fseek(file, pos, SEEK_SET);

	c = 'X';
	len = fwrite(&c, 1, 1, file);
	printf("write length:%d\n", len);

	int errno = fclose(file);
	printf("fclose errno:%d\n", errno);

	return 0;
}

単にfseekで現在位置を指定するだけである。そうすると中身がちゃんと書き換わるのである。
対策としてはfwriteの前にfseekを追加するか、読み書きは別の処理で行うかなどする必要があるだろう。

MinGWは速度重視らしいのでlinuxとの完全互換は捨てているのかもしれない。だがVisualStudioの方はどういうことだろうか・・・
Win32APIとの絡みな気もするが実装は追えていない。

C99の仕様(http://gcc.gnu.org/c99status.html)からしてみても問題なさそうだし、そもそも無意味な処理である現在位置にシークで書き込みが成功するというのはどう考えてもバグだろう。

cf.発端。コメント欄での言及。http://sigalrm.blogspot.jp/2011/10/cortex-m3-exception-vector-checksum.html

追記:Borland C++ Compiler 5.5でも同様の現象を確認 cf.https://downloads.embarcadero.com/free/c_builder

web拍手
This entry was posted in 未分類. Bookmark the permalink.

コメントを残す

メールアドレスが公開されることはありません。

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>