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