ページ 1 / 1
seekpについて教えてください。
Posted: 2008年12月15日(月) 18:47
by non
「猫でもわかる」の粂井さんのホームページで勉強中です。
さて、住所録を作ろうの所を行ってます。下のページです。
http://www.kumei.ne.jp/c_lang/cpp/cpp_38.htm
このままではVC2008ExpressEditionでエラーでしたので、修正しました。
それが添付ファイルです。
住所録を2回書き込んだとき、先頭にデータ件数、そのあとに2人分のデータが出力されなければ
いけないはずですが、2人目のデータしか書き込まれていません。すなわち、上書きされてます。
問題となる部分です。
Jout.open(JFILE, ios::out | ios::ate);
Jout.seekp(0, ios::beg);
Jout << no_of_data + 1 << endl;
Jout.seekp(0, ios::end);
Jout << data.name << endl;
さらに、まったく同じプログラムをBC++5.0で実行すると、すべてのデータが1件目の後に追加されます。
すなわち、先頭にシークできていません。
私の、何が間違っているのでしょうか?教えてください。
Re:seekpについて教えてください。
Posted: 2008年12月16日(火) 13:40
by non
どなたからも回答がいただけないので、スレッドが古くならないように自己レスです。
プログラムが長いと、見たくないという方のために、要点だけを抜き取ったプログラムです。
#include <iostream>
#include <fstream>
using namespace std;
void infile()
{
ifstream ifs;
char ch;
ifs.open("abc.txt");
ifs.seekg(4,ios::beg);
ifs >> ch;
cout << ch <<endl;
ifs.seekg(-4,ios::end);
ifs >> ch;
cout << ch <<endl;
ifs.close();
}
void outfile()
{
ofstream ofs;
ofs.open("abc.txt",ios::ate);
ofs.seekp(4,ios::beg);
ofs << 'E';
ofs.seekp(-4,ios::end);
ofs << 'Y';
ofs.close();
}
int main(void)
{
infile();
outfile();
return 0;
}
ファイル abc.txtの中身は
abcdefghijklmnopqrstuvwxyz
最後は改行して終わってます。
従って実行結果の予想は、eとyが画面に出た後、ファイルの中身がeがE、yがYになるはずでした。
実際に実行してみると、
最初に
e
y
とディスプレイに出力されるところまではいいのですが、
その後のファイル出力で、abc.txtは
VisualC++2008ExpressEditionの場合とgccの場合は
.Y..E (.はNULLです)になります。
バイナリエディタで見ると、00 59 00 00 45 です。
また、BorlandC++5.0の場合
abcdefghijklmnopqrstuvwxyz
EY
になります。
このようにコンパイラで結果が違うとともに、思った通りの動作をしません。
Re:seekpについて教えてください。
Posted: 2008年12月16日(火) 14:09
by non
再び、自己レスです。
Cで作成してみました。
#include <stdio.h>
void infile()
{
FILE *fp;
int ch;
fp=fopen("abc.txt","r");
fseek(fp,4,SEEK_SET);
ch=fgetc(fp);
putchar(ch);
fseek(fp,-4,SEEK_END);
ch=fgetc(fp);
putchar(ch);
fclose(fp);
}
void outfile()
{
FILE *fp;
fp=fopen("abc.txt","r+");
fseek(fp,4,SEEK_SET);
fputc('E',fp);
fseek(fp,-4,SEEK_END);
fputc('Y',fp);
fclose(fp);
}
int main(void)
{
infile();
outfile();
return 0;
}
これから言えることは、
ofs.open("abc.txt",ios::ate); は、
VC++2008の場合は、C言語の場合の
fp=fopen("abc.txt","w");のように働き、
BC++では
fp=fopen("abc.txt","a");のように働いているという事です。
C言語の"r+"のようなものはないのでしょうか?
Re:seekpについて教えてください。
Posted: 2008年12月16日(火) 14:30
by non
自己解決しました。
void outfile()
{
fstream ofs;
ofs.open("abc.txt",ios::in | ios::out);
ofs.seekp(4,ios::beg);
ofs << 'E';
ofs.seekp(-4,ios::end);
ofs << 'Y';
ofs.close();
}
正解かどうかは知りませんが、とにかく思った通り動きました。
Re:seekpについて教えてください。
Posted: 2008年12月16日(火) 22:07
by Justy
もう解決してしまっているようなので、ご参考までに。
Visual C++ 7.1/9.0ではこんな対応になっているようです。
[color=#d0d0ff" face="monospace]
ios_base::in "r"
ios_base::out "w"
ios_base::out | ios_base::trunc "w"
ios_base::out | ios_base::app "a"
ios_base::in | ios_base::binary "rb"
ios_base::out | ios_base::binary "wb"
ios_base::out | ios_base::trunc | ios_base::binary "wb"
ios_base::out | ios_base::app | ios_base::binary "ab"
ios_base::in | ios_base::out "r+"
ios_base::in | ios_base::out | ios_base::trunc "w+"
ios_base::in | ios_base::out | ios_base::app "a+"
ios_base::in | ios_base::out | ios_base::binary "r+b"
ios_base::in | ios_base::out | ios_base::trunc | ios_base::binary "w+b"
ios_base::in | ios_base::out | ios_base::app | ios_base::binary "a+b"[/color]
これとは別に ios_base::ate があった場合は fseek(fp, 0, SEEK_END) をしています。
# そのケースですと、ios_base::out | ios_base::appでも望み通りの動作になるのかもしれません。
Re:seekpについて教えてください。
Posted: 2008年12月17日(水) 08:34
by non
Justy さん。ご丁寧に、ありがとうございます。
あっちこっちのサイトを探しても情報がなく、苦労しました。
まして、ateの動作がコンパイラによって異なるとは、困ったものです。
もしかしたら、ateの動作が異なるのではなく、スイッチを省略したときの
defaultが異なるのかも知れませんが。
Re:seekpについて教えてください。
Posted: 2008年12月17日(水) 14:00
by たかぎ
少し調べてみました。
どうやら、Borland C++ Compiler 5.5.1のバグのようです。
少なくともBorland C++ Compiler 5.6.4では改善されています。
ボーランドの処理系は、バージョンによって標準C++ライブラリの実装がコロコロ変わるのが困ったものです。
なお、seekpは最終的にはstd::fseekを呼び出しますので、
> ofs.seekp(4,ios::beg);
> ofs.seekp(-4,ios::end);
のように、offsetに0またはtellpが返した値以外を指定した場合の動作は未定義だったはずです。
Re:seekpについて教えてください。
Posted: 2008年12月17日(水) 17:30
by non
たかぎさんへ
バグですか。了解しました。
>offsetに0またはtellpが返した値以外を指定した場合の動作は未定義だったはずです。
未定義ですか。しかし、欲しい機能ですよね。VCもBCも動いたのでよしとしましょう。