重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

【GOLF me!】初月無料お試し

元ネタ
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にならず,続きを読み込もうとして
クラッシュします。

どうやって回避するのが普通なのでしょう?

#バイト数を先に把握するってのも一つの手かもしれないけど,普通じゃないような気がする

A 回答 (3件)

よくある間違いですが,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バイト不足する事態が起きますよ。

この回答への補足

#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;
}

/* 一応エラーが出なくなったけど、こういうことだろうか? */

補足日時:2008/02/26 12:20
    • good
    • 0

>#とはいえ、俺自身は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.h …

この回答への補足

>半端なバイトデータがあったときに空読みが発生してるのを無視している
意図的にやってました。変数一個増やしてぐちゃぐちゃ書くのが悔しかったので。

#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;
}

補足日時:2008/02/26 16:37
    • good
    • 0

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;
}

この回答への補足

ご指摘の通り
俺のコードも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バイトですから,変な現象に遭うことはないんじゃないかなあと思ってますが・・・

#念のため,前置判定じゃなく、後置判定にしてみたけど駄目だった

補足日時:2008/02/26 11:35
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!