web-dev-qa-db-ja.com

C ++にバイナリメモリストリームはありますか

通常、stringstreamを使用してメモリ内の文字列に書き込みます。バイナリモードでcharバッファに書き込む方法はありますか?次のコードを検討してください。

stringstream s;
s << 1 << 2 << 3;
const char* ch = s.str().c_str();

chのメモリは次のようになります:0x313233-ASCII文字1、2、3のコード。バイナリ値自体を書き込む方法を探しています。つまり、メモリに0x010203が必要です。問題は、関数を書きたいことです。

void f(ostream& os)
{
    os << 1 << 2 << 3;
}

そして、使用するストリームの種類を外部で決定します。このようなもの:

mycharstream c;
c << 1 << 2 << 3; // c.data == 0x313233;
mybinstream b;
b << 1 << 2 << 3; // b.data == 0x010203;

何か案は?

52
FireAphis

文字列ストリームなどのバイナリデータをストリームに読み書きするには、read()およびwrite()メンバー関数を使用します。そう

unsigned char a(1), b(2), c(3), d(4);
std::stringstream s;
s.write(reinterpret_cast<const char*>(&a), sizeof(unsigned char));
s.write(reinterpret_cast<const char*>(&b), sizeof(unsigned char));
s.write(reinterpret_cast<const char*>(&c), sizeof(unsigned char));
s.write(reinterpret_cast<const char*>(&d), sizeof(unsigned char));

s.read(reinterpret_cast<char*>(&v), sizeof(unsigned int)); 
std::cout << std::hex << v << "\n";

これは与える 0x4030201私のシステムで。

編集:これを挿入演算子と抽出演算子(<<および>>)で透過的に動作させるには、正しいことを行う派生streambufを作成し、使用する任意のストリームに渡すことをお勧めします。

34
KeithB

この種のことはテンプレートを使用して行うことができます。例えば:

//struct to hold the value:
template<typename T> struct bits_t { T t; }; //no constructor necessary
//functions to infer type, construct bits_t with a member initialization list
//use a reference to avoid copying. The non-const version lets us extract too
template<typename T> bits_t<T&> bits(T &t) { return bits_t<T&>{t}; }
template<typename T> bits_t<const T&> bits(const T& t) { return bits_t<const T&>{t}; }
//insertion operator to call ::write() on whatever type of stream
template<typename S, typename T>
S& operator<<(S &s, bits_t<T> b) {
    return s.write((char*)&b.t, sizeof(T));
}
//extraction operator to call ::read(), require a non-const reference here
template<typename S, typename T>
S& operator>>(S& s, bits_t<T&> b) {
    return s.read((char*)&b.t, sizeof(T));
}

何らかのクリーンアップを使用できますが、機能します。例えば:

//writing
std::ofstream f = /*open a file*/;
int a = 5, b = -1, c = 123456;
f << bits(a) << bits(b) << bits(c);

//reading
std::ifstream f2 = /*open a file*/;
int a, b, c;
f >> bits(a) >> bits(b) >> bits(c);
4
Samuel Powell

さて、整数ではなく文字を使用してください。

s << char(1) << char(2) << char(3);
4

いくつかの珍しい演算子をオーバーロードすると、かなりうまく機能します。ここでは、<<と同じ左から右への結合性を持ち、何らかの形で近いルックアンドフィールを持つため、オーバーロードすることを選択しました<= ...

#include <iostream>
#include <stdint.h>
#include <arpa/inet.h>

using namespace std;

ostream & operator<= (ostream& cout, string const& s) {
    return cout.write (s.c_str(), s.size());
}
ostream & operator<= (ostream& cout, const char *s) {
    return cout << s;
}
ostream & operator<= (ostream&, int16_t const& i) {
    return cout.write ((const char *)&i, 2);
}
ostream & operator<= (ostream&, int32_t const& i) {
    return cout.write ((const char *)&i, 4);
}
ostream & operator<= (ostream&, uint16_t const& i) {
    return cout.write ((const char *)&i, 2);
}
ostream & operator<= (ostream&, uint32_t const& i) {
    return cout.write ((const char *)&i, 4);
}

int main() {
    string s("some binary data follow : ");

    cout <= s <= " (machine ordered) : " <= (uint32_t)0x31323334 <= "\n"
         <= s <= " (network ordered) : " <= htonl(0x31323334) ;
    cout << endl;

    return 0;
}

いくつかの欠点があります:

  • <=の新しい意味は、読者を混乱させたり、予期しない結果につながる可能性があります。

    cout <= 31 <= 32;
    

    と同じ結果を与えません

    cout <= (31 <= 32);
    
  • 上記の例に示すように、コードを読む際にエンディアンが明確に言及されていません。

  • 同じ優先グループに属していないため、単純に<<と混合することはできません。私は通常、括弧を使用して次のようなことを明確にします。

    ( cout <= htonl(a) <= htonl(b) ) << endl;
    
3

このユースケースでは、「rawシフト演算子」を自分で実装しました。

_template <typename T, class... StreamArgs>
inline std::basic_ostream<StreamArgs...> &
operator <= (std::basic_ostream<StreamArgs...> & out, T const & data) {
        out.write(reinterpret_cast<char const *>(&data), sizeof(T));
        return out;
}
_

便利な場所に置き、次のように使用します。

_std::cout <= 1337 <= 1337ULL <= 1337. <= 1337.f;
_

利点:

  • チェーン可能
  • 自動sizeof()
  • 配列と構造体/クラスインスタンスも受け取ります

短所:

  • 非PODオブジェクトでは安全ではありません:ポインターとパディングをリークします
  • 出力はプラットフォーム固有です:パディング、エンディアネス、整数型
2
kamikaze