Simpler way to create a C++ memorystream from (char*, size_t), without copying the data?
I'm assuming that your input data is binary (not text), and that you want to extract chunks of binary data from it. All without making a copy of your input data.
You can combine boost::iostreams::basic_array_source
and boost::iostreams::stream_buffer
(from Boost.Iostreams) with boost::archive::binary_iarchive
(from Boost.Serialization) to be able to use convenient extraction >> operators to read chunks of binary data.
#include <stdint.h>
#include <iostream>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/archive/binary_iarchive.hpp>
int main()
{
uint16_t data[] = {1234, 5678};
char* dataPtr = (char*)&data;
typedef boost::iostreams::basic_array_source<char> Device;
boost::iostreams::stream_buffer<Device> buffer(dataPtr, sizeof(data));
boost::archive::binary_iarchive archive(buffer, boost::archive::no_header);
uint16_t word1, word2;
archive >> word1 >> word2;
std::cout << word1 << "," << word2 << std::endl;
return 0;
}
With GCC 4.4.1 on AMD64, it outputs:
1234,5678
Boost.Serialization is very powerful and knows how to serialize all basic types, strings, and even STL containers. You can easily make your types serializable. See the documentation. Hidden somewhere in the Boost.Serialization sources is an example of a portable binary archive that knows how to perform the proper swapping for your machine's endianness. This might be useful to you as well.
If you don't need the fanciness of Boost.Serialization and are happy to read the binary data in an fread()-type fashion, you can use basic_array_source
in a simpler way:
#include <stdint.h>
#include <iostream>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
int main()
{
uint16_t data[] = {1234, 5678};
char* dataPtr = (char*)&data;
typedef boost::iostreams::basic_array_source<char> Device;
boost::iostreams::stream<Device> stream(dataPtr, sizeof(data));
uint16_t word1, word2;
stream.read((char*)&word1, sizeof(word1));
stream.read((char*)&word2, sizeof(word2));
std::cout << word1 << "," << word2 << std::endl;
return 0;
}
I get the same output with this program.
looking for a MemoryStream in C++
#include <sstream>
std::ostringstream buffer; // no growth specification necessary
buffer << "a char buffer" << customObject << someOtherObject;
std::string contents = buffer.str();
size_t bufferSize = contents.size();
rawNetworkSocket.Send(contents); // you can take the size in Send
Using this approach you will have to parse the result where you receive it (as the code above just transforms your data into an unstructured string.
Another problem with it is that since C++ doesn't support reflection, you will have to define operator << for your objects. This is the code for a Custom
class:
template<typename C, typename T>
std::basic_ostream<C,T>& operator << (
std::basic_ostream<C,T>& out, const Custom& object)
{
out << object.member1 << "," << object.member2 /* ... */ << object.memberN;
return out;
}
If you want structured serialization, have a look at boost::serialization.
initializing a C++ std::istringstream from an in memory buffer?
Look at std::istrstream it has a constructor
istrstream( char* pch, int nLength );
This class is sort of depreciated or at least you are normally told to use other classes.
The issue with strstream is that it is more complex to manage the memory of the char* buffer so in general you would prefer stringstream as it does the memory management for you. However in this case you are already managing the memory of the char* so the normal benefit is in this case a cost. In fact in this case strstream does exactly what you want with minimal overhead in code or speed. This is similar to the discussion of ostrsteram by Herb Sutter
initializing a C++ std::istringstream from an in memory buffer?
Look at std::istrstream it has a constructor
istrstream( char* pch, int nLength );
This class is sort of depreciated or at least you are normally told to use other classes.
The issue with strstream is that it is more complex to manage the memory of the char* buffer so in general you would prefer stringstream as it does the memory management for you. However in this case you are already managing the memory of the char* so the normal benefit is in this case a cost. In fact in this case strstream does exactly what you want with minimal overhead in code or speed. This is similar to the discussion of ostrsteram by Herb Sutter
How can I read from memory just like from a file using iostream?
I found a solution that works on VC++ since Nim solution works only on GCC compiler (big thanks, though. Thanks to your answer I found other answers which helped me!).
It seems that other people have similar problem too. I did exactly as here and here.
So to read from a piece of memory just like form a istream you have to do this:
class membuf : public streambuf
{
public:
membuf(char* p, size_t n) {
setg(p, p, p + n);
}
};
int main()
{
char buffer[] = "Hello World!\nThis is next line\nThe last line";
membuf mb(buffer, sizeof(buffer));
istream istr(&mb);
string line;
while(getline(istr, line))
{
cout << "line:[" << line << "]" << endl;
}
}
EDIT: And if you have '\r\n' new lines do as Nim wrote:
if (*line.rbegin() == '\r') line.erase(line.end() - 1);
I'm trying to treat this memory as as wistream
. Does anybody know how to do this? I asked separate question for this.
convert from string to byte[] and add the result into a memorystream
You can get a pointer to the string buffer by simply calling std::string.c_str()
. That will return a const char*
(where char
is an int8_t
) that you can effectively use as a byte[]
. Keep in mind though that the pointer returned is pointing to memory managed by the string object, so if you change anything in the original string class, you will invalidate the pointer. Also since it's a pointer to a const char
, you shouldn't change any values in the buffer. So if you need more permanent memory, or need a buffer you can modify, a better way to accomplish your goal would be to-do (using gcc, which shouldn't be a problem since you're on Ubuntu):
std::string my_string;
char string_array[my_string.length() + 1];
strcpy(string_array, my_string.c_str());
Now use the string_array
as your memory buffer.
If you need to return the buffer from a function, you're going to have to allocate the buffer on the heap and return a pointer. That also means you're going to have to call delete []
on the pointer as well after you're done with it, or else you're going to end up with a memory leak. So you could do the following:
#include <string>
#include <cstring>
char* return_buffer(const std::string& string)
{
char* return_string = new char[string.length() + 1];
strcpy(return_string, string.c_str());
return return_string;
}
//now use in code
int main()
{
std::string some_string = "Stuff";
char* buffer = return_buffer(some_string);
//...do something with buffer
//...after you're done with the buffer to prevent memory leak
delete [] buffer;
return 0;
}
C++ memory stream to C file stream
If you're on a GNU system, (Linux, Glibc), you can use fopencookie
to create a FILE *
wrapper for your decoding operation:
FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs);
[...]
The fopencookie() function serves a purpose similar to fopen(3): it
opens a new stream and returns a pointer to a FILE object that is
used to operate on that stream.The cookie argument is a pointer to the caller's cookie structure
that is to be associated with the new stream. This pointer is
supplied as the first argument when the standard I/O library invokes
any of the hook functions described below.The mode argument serves the same purpose as for fopen(3). The
following modes are supported: r, w, a, r+, w+, and a+. See fopen(3)
for details.The io_funcs argument is a structure that contains four fields
pointing to the programmer-defined hook functions that are used to
implement this stream. The structure is defined as followstypedef struct {
cookie_read_function_t *read;
cookie_write_function_t *write;
cookie_seek_function_t *seek;
cookie_close_function_t *close;
} cookie_io_functions_t;
[...]
(I didn't want to copy the entire manpage to my answer).
Basically then you can do:
ssize_t my_read(void *cookie, char *buf, size_t size) {
std::istream *the_stream = static_cast<std::istream*>(cookie);
// insert magic
return bytes_read;
}
cookie_io_functions_t my_functions = {
my_read,
NULL,
NULL,
NULL,
};
...
FILE *wrapped = fopencookie(static_cast<void *>&stream, "rb", my_functions);
On BSD/OSX, you'd be equally lucky, because it comes with funopen
which is just a slightly different API to achieve exactly the same thing.
And if you want to support Windows, well, poor you.
Could I use stringstream as a memory stream like `MemoryStream` in C#?
When storing character sequences in a std::string
you can have included null characters. Correspondingly, a std::stringstream
can deal with embedded null characters as well. However, the various formatted operations on streams won't pass through the null characters. Also, when using a built-in string to assign values to a std::string
the null characters will matter, i.e., you'd need to use the various overloads taking the size of the character sequence as argument.
What exactly are you trying to achieve? There may be an easier approach than traveling in string streams. For example, if you want to read the stream interface to interact with a memory buffer, a custom stream buffer is really easy to write and setup:
struct membuf
: std::streambuf
{
membuf(char* base, std::size_t size) {
this->setp(base, base + size);
this->setg(base, base, base + size);
}
std::size_t written() const { return this->pptr() - this->pbase(); }
std::size_t read() const { return this->gptr() - this->eback(); }
};
int main() {
// obtain a buffer starting at base with size size
membuf sbuf(base, size);
std::ostream out(&sbuf);
out.write("1\08\09\0", 6); // write three digits and three null chars
}
Related Topics
Looking for 16-Bit X86 Compiler
Edges on Polygon Outlines Not Always Correct
Why Is Operator!= Removed in C++20 for Many Standard Library Types
A Way in C++ to Hide a Specific Function
How to Pass Multiple Ints into a Vector at Once
Implicit Conversion When Overloading Operators for Template Classes
True Isometric Projection with Opengl
Ways to Do Modulo Multiplication with Primitive Types
Is There Some Ninja Trick to Make a Variable Constant After Its Declaration
Convert a C++ Program to a Windows Service
In C/C++, Is Char* Arrayname[][] a Pointer to a Pointer to a Pointer or a Pointer to a Pointer
How to Increment an Iterator by Just Adding a Number
Getting an Array of Bytes Out of Windows::Storage::Streams::Ibuffer
C++11 Virtual Destructors and Auto Generation of Move Special Functions