AUTOEXECと申します。表題の件、質問させてください。
当方の環境は、WinXP(SP2) VC++2003です。
バイナリーファイル(たとえば画像ファイル等)を一旦メモリ上にバッファリングし、
さらに、フォーマットに準じた構造体メンバに格納する際、
std::istreamを使用して、スマートな実装を行いたい(※)と考えています。
(※)
下記のように、operator>>を使用して解決したいと考えています。
iss: メモリ上のバッファを入力とするストリーム
member1~4:フォーマット上のサイズに合わせたメンバ
iss >> member1 >> member2 >> member3 >> member 4;
別方法(単純なメモリコピーの繰り返し)では、要件を実現しているのですが、
std::istreamでよりスマートに実装する方法があるとのことで、
コーディングの効率化のため、調査しています。
下記、サンプルプログラムにて、入力ストリームから情報が取れず、困っています。
大変お手数をおかけしますが、当方のどの点に問題あるか、ご指摘いただけますでしょ
うか?
よろしくお願い致します。
=================================================
#include <stdio.h>
#include <iostream>
#include <strstream>
//4バイトのデータを管理するクラス
class N4
{
private:
int mVal;
public:
N4() {Clear();};
N4( const int& val ) {this->mVal = val;};
~N4() {};
void Clear() {this->mVal = 0;return;};
friend std::istream & operator >>( std::istream &lhs , N4 &rhs ){
return lhs >> rhs.mVal; };
};
// 実際には、上記N4クラスに似たクラスをhas-a関係で組み合わせて、
// ファイルフォーマットを構築しています。ここでは簡単のため、
// 上記N4クラスに、データを挿入することに着目します。
void main(){
char buf[4] = { 127, 126, 125, 124 }; //ファイルのイメージとす
る。(仮)
std::istrstream istr( buf, 4 ); //入力ストリー
ム作成
N4 n4 = -1;
//N4型生成
istr >> n4;
//N4型へストリームから入力←うまくいかない
return;
}
=================================================
#include <iostream>
#include <sstream>
class N4 {
private:
int mVal, nVal;
public:
N4() {Clear();};
N4( const int& val ) {this->mVal = val;};
~N4() {};
void Clear() {this->mVal = 0;return;};
void dump() const {
const char* p = reinterpret_cast<const char*>(&mVal);
for ( int i = 0; i < 4; ++i ) {
std::cout << static_cast<int>(*p++) << ' ';
}
std::cout << std::endl;
}
friend std::istream & operator >>( std::istream &lhs , N4 &rhs ) {
char* p = reinterpret_cast<char*>(&rhs.mVal);
lhs.get(*p++);
lhs.get(*p++);
lhs.get(*p++);
lhs.get(*p++);
return lhs;
}
};
int main() {
char buf[4] = { 127, 126, 125, 124 };
std::istringstream istr(std::string(buf,4));
N4 n4(0);
istr >> n4;
n4.dump();
}
επιστημη様
AUTOEXECです。早速のご指摘ありがとうございます。
こちらのプログラムでは、operator>>定義と、
strstringを使用している点がまずいということが理解できました。
大変助かりました。
追加で質問させてください。
事例でいただきましたプログラムの、operator>>は、
1つめの変数では正しく動作するのですが、
2つめ以降で、入力ストリームからデータを取得できないようです。
funcA(): istr >> n >> m; //連続で取得
funcB(): istr >> n; istr >> m; //分割で取得
↑双方共に、nだけデータが取得でき、mでは取得できませんでした。
重ね重ねお手数をおかけしますが、
どの点に問題あるか、ご指摘いただけますでしょうか?
======================================================
#include <iostream>
#include <sstream> //istringstream
using namespace std;
class N4
{
private:
int mVal;
public:
N4() {Clear();};
N4( const int& val ) {this->mVal = val;};
~N4() {};
void Clear() {this->mVal = 0;return;};
void dump()const{
const char* p = (char*)(&mVal);
for( int i=0; i<4; i++ ){
std::cout << static_cast<int>(*p++) << ' ';
}
std::cout << std::endl;
}
friend std::istream & operator >>( std::istream &lhs , N4 &rhs ){
char* p = reinterpret_cast<char*>(&rhs.mVal);
lhs.get(*p++); //p[0]を取得し、ポインタをずらず。
lhs.get(*p++); //p[1]を取得し、ポインタをずらず。
lhs.get(*p++); //p[2]を取得し、ポインタをずらず。
lhs.get(*p++); //p[3]を取得し、ポインタをずらず。
return lhs >> rhs.mVal;
};
};
void funcA(){
char buf[8] = { 127, 126, 0, 124, 123, 122, 0, 120 };
std::istringstream istr(std::string(buf,8));
N4 n(0);
N4 m(0);
istr >> n >> m;
n.dump();
m.dump();
return;
};
void funcB(){
char buf[8] = { 127, 126, 0, 124, 123, 122, 0, 120 };
std::istringstream istr(std::string(buf,8));
N4 n(0);
istr >> n;
n.dump();
N4 m(0);
istr >> m;
m.dump();
return;
};
void main(void)
{
funcA();
funcB();
return;
}
friend std::istream & operator >>( std::istream &lhs , N4 &rhs ){
char* p = reinterpret_cast<char*>(&rhs.mVal);
lhs.get(*p++); //p[0]を取得し、ポインタをずらず。
lhs.get(*p++); //p[1]を取得し、ポインタをずらず。
lhs.get(*p++); //p[2]を取得し、ポインタをずらず。
lhs.get(*p++); //p[3]を取得し、ポインタをずらず。
× return lhs >> rhs.mVal;
○ return lhs;
};
επιστημη様
AUTOEXECです。解決しました。
当方のミス含め、ご回答(解答?)いただき、大変助かりました。
以下、まとめさせていただきます。
■ メモリ上にバッファしたバイナリデータを、 ■
■ std::istreamを使用してオブジェクトへ格納する方法 ■
例) iss >> member1 >> member2 >> member3 >> member 4;
1.std::istringstreamを使用する。
→std::istrstreamでは、NULL以降がカットされる。includeは、<sstream>を使用。
2.operator>>を、クラスごとに定義。
→入力ストリームへの操作を実施。返値は左辺をそのまま返す。
以下、サンプルコード↓
====================================================
#include <iostream>
#include <iomanip>
#include <sstream> //istringstream
#include <strstream> //istrstream
using namespace std;
class N4
{
private:
unsigned int mVal;
public:
N4() {Clear();};
N4( const int& val ) {this->mVal = val;};
~N4() {};
void Clear() {this->mVal = 0;return;};
void dump()const{
const unsigned char* p = (unsigned char*)(&mVal);
cout << [ ;
for( int i=0; i<4; i++ ){
cout.width(2); cout << uppercase;
unsigned int A = static_cast<unsigned char>(*p++);
cout << hex << A << ' ';
}
cout << ] << endl;
}
friend istream & operator >>( istream &lhs , N4 &rhs ){
char* p = reinterpret_cast<char*>(&rhs.mVal);
lhs.get(*p++);
lhs.get(*p++)
lhs.get(*p++);
lhs.get(*p++);
return lhs;
};
};
void Dump( string str, N4& n, N4& m ){
cout << str << endl;
cout << n:; n.dump();
cout << m:; m.dump();
cout << endl;
}
void funcX( unsigned char* buf, int size, string str ){
istrstream istr( (char*)buf );
N4 n(0);N4 m(0);
istr >> n >> m;
Dump( str, n, m );
};
void funcY( unsigned char* buf, int size, string str ){
istringstream istr(string((char*)buf,8));
N4 n(0);N4 m(0);
istr >> n >> m;
Dump( str, n, m );
};
void main()
{
unsigned char buf1[8] = { 0xFF, 0xEE, 0xBB, 0xAA, 0x88, 0x44, 0x22, 0x11 };
unsigned char buf2[8] = { 0xFF, 0xEE, 0, 0xAA, 0x88, 0x44, 0, 0x11 };
cout << istrstreamを使用した場合 << endl;
funcX( buf1, sizeof(buf1), 途中にNULLを含まない場合 );
funcX( buf2, sizeof(buf2), 途中にNULLを含む場合 );
cout << istringstreamを使用した場合 << endl;
funcY( buf1, sizeof(buf1), 途中にNULLを含まない場合 );
funcY( buf2, sizeof(buf2), 途中にNULLを含む場合 );
}
====================================================
ここまで↑
実行結果↓
====================================================
istrstreamを使用した場合
途中にNULLを含まない場合
n:[ FF EE BB AA ]
m:[ 88 44 22 11 ]
途中にNULLを含む場合
n:[ FF EE 0 0 ]
m:[ 0 0 0 0 ]
istringstreamを使用した場合
途中にNULLを含まない場合
n:[ FF EE BB AA ]
m:[ 88 44 22 11 ]
途中にNULLを含む場合
n:[ FF EE 0 AA ]
m:[ 88 44 0 11 ]
====================================================
↑ここまで
※istringstreamを使用した場合、NULLを含むデータも、正しく読み込めました。