English 中文(简体)
C++有双亲记忆流
原标题:Are there binary memory streams in C++
  • 时间:2009-10-13 10:01:33
  •  标签:

我通常使用<条码>载荷,在网上书写。 是否有办法用双轨方式写给“沙尔缓冲”? 考虑以下法典:

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

<代码>ch上的记忆将照此办理:0x313233-ASCII 性质代码1、2和3。 我期望找到一种方式来写双币值本身。 这就是说,我要缅怀0x10203。 问题是,我希望能够写出一项职能。

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;

任何想法?

问题回答

阅读和书写双向数据,包括直流,使用()和书写()成员职能。 So

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

该系统<0x4030201。

Edit: To make this work transparently with the insertion and extraction operators (<< and >>), your best bet it to create a derived streambuf that does the right thing, and pass that to whatever streams you want to use.

你可以用模板来做这种事情。 例如:

//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);

同样,公正的使用性质,而不是煽动。

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

卸载一些非同寻常的运营商的工作相当顺利。 下面我选择超负荷工作:<=,因为它与<有相同的左对右联系;<,并且有近视线与feel。

#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 <= "
"
         <= s <= " (network ordered) : " <= htonl(0x31323334) ;
    cout << endl;

    return 0;
}

有几个缺点:

  • <=的新含义可能混淆读者或导致意外结果:

    cout <= 31 <= 32;
    

    赢得同样的结果

    cout <= (31 <= 32);
    
  • the endianess isn t clearly mentionned at reading the code, as illustrated in the above example.

  • it cannot mix simply with << because it doesn t belong to the same group of precedence. I usually use parenthesis to clarify such as :

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

为此,我实施了“转船经营人”:

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;

优点:

  • chainable
  • automatic sizeof()
  • takes arrays and struct/class instances, too

缺点:

  • unsafe for non-POD objects: leaks pointers and padding
  • output is platform specific: padding, endianess, integer types
#include <sstream>

class bostringstream {
public:
  bostringstream() : oss() {}

  template <typename T, typename std::enable_if<std::is_fundamental<T>::value,
                                                bool>::type = true>
  bostringstream& operator<<(const T& v) {
    oss.write((char*)&v, sizeof(T));
    return *this;
  }

  template <typename T, typename std::enable_if<
                            std::is_fundamental<typename T::value_type>::value,
                            bool>::type = true>
  bostringstream& operator<<(const T& v) {
    oss.write((char*)v.data(), v.size() * sizeof(typename T::value_type));
    return *this;
  }

  template <typename _InputIterator>
  bostringstream& write(_InputIterator first, _InputIterator last) {
    char* data = (char*)&(*first);
    auto n = std::distance(first, last);
    oss.write(data, n * sizeof(*first));
    return *this;
  }

  template <typename T, typename std::enable_if<std::is_fundamental<T>::value,
                                                bool>::type = true>
  bostringstream& write(const T* v, std::streamsize count) {
    oss.write((char*)v, sizeof(T) * count);
    return *this;
  }

  auto rdbuf() const { return oss.rdbuf(); }

  auto str() const { return oss.str(); }

  std::size_t size() { return oss.tellp(); }

protected:
  std::ostringstream oss;
};

例:

#include <array>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include "bsstream.hpp"

int main(int argc, char **argv) {

  int i = 1;
  float j = 1.1;
  double k = 1.2;
  std::vector<int> ii{1,2};
  std::vector<double> jj{1.2,2.2};
  std::string kk = "abcd";
  std::array<int, 2> ll{3,4};
  int l[] = {1,2};

  bostringstream of;
  of << i << j <<k;
  of <<ii << jj << kk << ll;
  of.write(l, 2);

  std::ofstream oof("foo.bin", std::ios::binary);
  oof << of.str();
  oof.close();

}

并非一种可取的解决办法,而是运作和灵活

我确实喜欢汉·卢奥的做法,并且已经核实它会做伟大的工作! 如果将变体成员变量换成固定用途:stringstream (vs. ostringstream),这一类别也可用于具有超负荷流出的采掘经营者的提炼:

    template <typename T, typename std::enable_if<std::is_fundamental<T>::value, bool>::type = true>
    bostringstream& operator>> (T& v)
    {
        char buffer[sizeof(T)];
        oss.read(buffer, sizeof(T));
        v = *(T*)buffer;
        return *this;
    }

实例模板支持了整体类型,如果添加一个新的模板,用于下列方面:即: 象 st子一样,即“是资金”,我建议首先将规模推向下游,这样,在提炼方面,就可以吸引它知道有多少要素在后撤。 这种办法可以与共同的方面合作:即:地图类型相当高。





相关问题
热门标签