• ベストアンサー

EOFにならない?

元ネタ http://oshiete1.goo.ne.jp/qa3809521.html /* C# */ using System; namespace Q3809521A { class Q3809521A { public static void Main(string[] args) { byte[] b1 = {0x42,0xb9,0xe0,0xa4,0x3b,0xdf,0xea,0xc0,0x3a,0x70,0xeb,0xdc,0x37,0x7c,0xf4,0x8c}; System.IO.FileStream f = new System.IO.FileStream("C:\\hogefuga.bin",System.IO.FileMode.Create, System.IO.FileAccess.Write); f.Write(b1,0,b1.Length); System.Console.WriteLine(BitConverter.ToString(b1)); f.Close(); System.Console.ReadKey(true); } } } という風に作ったhogefuga.binを bccでコンパイルした以下のプログラムで読み込ませたところ, #include <iostream> #include <fstream> int main () { unsigned char buf[4]; float *hoge; std::ifstream ifs ( "hogefuga.bin" , std::ifstream::in ); while(!ifs.eof()){ // Debug // std::cout << (ifs.eof() == true ? "TRUE" : "FALSE") << std::endl ; for (int i = 0;i < 4;i++ ){ buf[3 - i] = (unsigned char) ifs.get(); } hoge = (float *)buf; std::cout << (*hoge) <<std::endl; } ifs.close(); return 0; } 92.9388 0.0068334 0.000919042 1.50773e-05 と、期待通り表示された後も ifs.eof()がtrueにならず,続きを読み込もうとして クラッシュします。 どうやって回避するのが普通なのでしょう? #バイト数を先に把握するってのも一つの手かもしれないけど,普通じゃないような気がする

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

よくある間違いですが,CのfeofやC++のbasic_ios::eof()は,何らかの読み込み処理をした結果がEOFだった場合に真を返すようになります。 今回の場合,ifs.get()がstd::char_traits<char>::eof()を返したタイミングで,basic_ios::eof()がtrueを返すようになります。 そのため,ifs.get()で判別しなければなりません。 あと,コンストラクタでinの他にbinaryを指定しておかないと,0x0D 0x0Aが含まれた場合などに0x0D扱いされて1バイト不足する事態が起きますよ。

himajin100000
質問者

補足

#include <iostream> #include <fstream> int main () { unsigned char buf[4]; float *hoge; std::ifstream ifs ( "hogefuga.bin" , std::ifstream::in | std::ifstream::binary ); while(true){ for (int i = 0;i < 4;i++ ){ buf[3 - i] = (unsigned char) ifs.get(); } if ( !ifs.eof() ){ hoge = (float *)buf; std::cout << (*hoge) << std::endl; /* エラーは EOFだった時にここで出ているようだ */ }else{ break; } } ifs.close(); return 0; } /* 一応エラーが出なくなったけど、こういうことだろうか? */

すると、全ての回答が全文表示されます。

その他の回答 (2)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.3

>#とはいえ、俺自身はNANを表示させるコードのつもりはなかったんですが >何で表示されているんだろう・・・(NANの時にeofになるんだと思ってた) これは#2の方の説明にあるように、ファイルの末尾に達して(最後のキャラクタを読んだ状態で)から さらに読み進めてたときに eof() が true になるので、 >while(!ifs.eof()){ これだとかならず末尾に一つゴミデータが発生します。 そのゴミがたまたま VC++もg++もNaNとみなすような ものだったということでしょう。 #って、全bit Onのデータになるのかな? > while(true){ > for (int i = 0;i < 4;i++ ){ > buf[3 - i] = (unsigned char) ifs.get(); > } > >if ( !ifs.eof() ){ 半端なバイトデータがあったときに空読みが発生してるのを無視している (unsigned charにキャストしている)のが気になりますが ゴミデータはでないですね。 まあ好みの問題ですが、わたしなら ifsteram.read() で sizeof (float) 読み込んでおいて その結果を swap するなどします。 C++入出力 http://www.cppll.jp/cppreference/cppio_details.html

himajin100000
質問者

補足

>半端なバイトデータがあったときに空読みが発生してるのを無視している 意図的にやってました。変数一個増やしてぐちゃぐちゃ書くのが悔しかったので。 #include <iostream> #include <fstream> int main () { unsigned char buf[4]; float *hoge; std::ifstream ifs ( "hogefuga.bin" , std::ifstream::in | std::ifstream::binary ); while(true){ for (int i = 0;i < 4;i++ ){ unsigned char c = (unsigned char) ifs.get(); if ( c != (unsigned char) std::char_traits<char>::eof()){ buf[3 - i] = c; }else{ break; } } if ( !ifs.eof() ){ hoge = (float *)buf; std::cout << (*hoge) << std::endl; }else{ break; } } ifs.close(); return 0; }

すると、全ての回答が全文表示されます。
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.1

eof の判定位置がよろしくないような気がしますがそれはおいといても VC++ 92.9388 0.0068334 0.000919042 1.50773e-005 -1.#QNAN g++ 92.9388 0.0068334 0.000919042 1.50773e-05 nan のどちらも、NaNを出力した後で正常終了してます。 クラッシュというのはSEGVでもおきているんでしょうか? #include <iostream> #include <fstream> int main () { unsigned char buf[4]; float *hoge; std::ifstream ifs ( "hogefuga.bin" , std::ifstream::in ); while(!ifs.eof()){ // Debug // std::cout << (ifs.eof() == true ? "TRUE" : "FALSE") << std::endl ; for (int i = 0;i < 4;i++ ){ buf[3 - i] = (unsigned char) ifs.get(); } #if 0 if (ifs.eof()) { std::cerr << "quit (1)" << std::endl; break; } #endif hoge = (float *)buf; std::cout << (*hoge) <<std::endl; #if 0 #ifdef HAVE_ISNAN if (isnan(*hoge)) { std::cerr << "quit (2)" << std::endl; break; } #else float x; float y; x = *hoge; y = *hoge; if (x!=y) { std::cerr << "quit (2)" << std::endl; break; } #endif #endif } ifs.close(); return 0; }

himajin100000
質問者

補足

ご指摘の通り 俺のコードもsakusaker7さんに書いてもらったコードも, g++/MinGW v5.1.3(installer) では正常終了します。 #とはいえ、俺自身はNANを表示させるコードのつもりはなかったんですが 何で表示されているんだろう・・・(NANの時にeofになるんだと思ってた) #個人的にあまり色々入れたくないのでVC++は入れてません。 (俺のコード) bcc32 5.5.1 ================== q3810761-1.exe - アプリケーションエラー 例外 unknown software exception (0xc0000090)がアプリケーションの0x004117e1で発生しました。 q3810761-1.exe - アプリケーションエラー 例外 unknown software exception (0xc0000090)がアプリケーションの0x004117e1で発生しました。 q3810761-1.exe - アプリケーションエラー 例外 unknown software exception (0xc0000027)がアプリケーションの0x7c80df2cで発生しました。 ============================== >eof の判定位置がよろしくないような気がしますが これはどのような理由でしょうか? 確かに,4(sizeof(float))バイトで割り切れないファイルがあった時,eofになるのか疑問ですが,今回は16バイトですから,変な現象に遭うことはないんじゃないかなあと思ってますが・・・ #念のため,前置判定じゃなく、後置判定にしてみたけど駄目だった

すると、全ての回答が全文表示されます。

関連するQ&A