Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there binary memory streams in C++

Tags:

c++

iostream

I usually use stringstream to write into in-memory string. Is there a way to write to a char buffer in binary mode? Consider the following code:

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

The memory at ch will look like this: 0x313233 - the ASCII codes of the characters 1, 2 and 3. I'm looking for a way to write the binary values themselves. That is, I want 0x010203 in the memory. The problem is that I want to be able to write a function

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

And decide outside what kind of stream to use. Something like this:

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

Any ideas?

like image 951
FireAphis Avatar asked Oct 13 '09 10:10

FireAphis


2 Answers

To read and write binary data to streams, including stringstreams, use the read() and write() member functions. 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 << "\n"; 

This gives 0x4030201 on my system.

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.

like image 87
KeithB Avatar answered Sep 20 '22 07:09

KeithB


You can do this sort of thing with templates. E.g:

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

It could use some cleanup, but it's functional. E.g:

//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); 
like image 27
Samuel Powell Avatar answered Sep 20 '22 07:09

Samuel Powell