Are there binary memory streams in C ++

I usually use stringstream to write to a string in memory. Is there a way to write 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 in ch will look like this: 0x313233 - ASCII codes of characters 1, 2 and 3. I'm looking for a way to write the binary values ​​themselves. That is, I want 0x010203 in memory. The problem is that I want to write a function

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

And decide which stream to use. Something like that:

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

Any ideas?

+50
c ++ iostream
Oct 13 '09 at 10:01
source share
4 answers

To read and write binary data to streams, including string streams, use the read () and write () 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 insert and extract operators (<<and →), it is best to create a streambuf derivative for it that does the right thing, and pass that to the threads you want to use.

+30
Oct 13 '09 at 11:14
source share

Well, just use characters, not integers.

 s << char(1) << char(2) << char(3); 
+5
Oct 13 '09 at 10:05
source share

overloading some unusual operators works pretty well. Here below, I decided to overload <= , because it has the same association from left to right as < , and has a somewhat close appearance ...

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

There are several disadvantages:

  • the new meaning <= may confuse readers or lead to unexpected results:

     cout <= 31 <= 32; 

    will not give the same result as

     cout <= (31 <= 32); 
  • endianess is not explicitly mentioned when reading the code, as shown in the above example.

  • it cannot simply mix with << because it does not belong to the same priority group. I usually use parentheses for like:

     ( cout <= htonl(a) <= htonl(b) ) << endl; 
+1
Mar 15 '13 at 17:39
source share

In this case, I implemented the "shift shift operator" itself:

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

Place it somewhere conveniently and use it like this:

 std::cout <= 1337 <= 1337ULL <= 1337. <= 1337.f; 

Benefits:

  • chain
  • automatic sizeof()
  • also accepts arrays and instances of struct / class

Disadvantages:

  • unsafe for objects other than POD: leak indicators and indentation
  • platform-specific output: padding, endianess, integer types
0
Jan 13 '17 at 13:11
source share



All Articles