Reputation:
I want to write a custom binary file for my little game engine. I worked with C# and I know how to do it in C# with BitConvert or Convert.
But for some reasons I need to do the same in C++.
Here's my data struct :
Mesh Position point3(x,y,z) type: float size: 4bytes *3 = 12bytes
Mesh Options point3(b1,b2,b3) type: bool size: 1byte *3 = 3bytes
Mesh Scale point3(x,y,z) type: int size: 4bytes *3 = 12bytes
Mesh Tag single type: string size: 8bytes *1 = 8bytes
Now I have an list of unsigned chars :
vector<unsigned char> binary_data;
And I can use push to add single bytes into it and finally write it with ofstream :
ofstream fout;
fout.open("file.bin", ios::binary | ios::out);
vector<unsigned char> binary_data;
binary_data.push_back(0x66);
binary_data.push_back(0xFF); // bool : true
binary_data.push_back(0x00); // bool : false
fout.write((char*)binary_data.data(),binary_data.size());
fout.close();
I need to convert my values of any type float,int,bool,uint,double to byte array and append it to my vector list.
And again get them and convert them back to original value.
offsets and byte sizes are all known.
Here's an example : There's two meshes in scene ..
Now I get x y z and convert them to 4 bytes :
10 = > 00 00 00 0A
5 = > 00 00 00 05
15 = > 00 00 00 0F
25 = > 00 00 00 19
0 = > 00 00 00 00
5 = > 00 00 00 05
And I append them to binary_data
list.
How can I convert them to byte array and back ?
Upvotes: 1
Views: 1925
Reputation: 19223
You could use std::memcpy
like this:
#include <cstring>
#include <vector>
#include <type_traits>
template <typename T> void serialize(std::vector<char> &v, const T &obj) {
static_assert(std::is_trivially_copyable<T>::value,"Can only serialize trivially copyable objects.");
auto size = v.size();
v.resize(size + sizeof(T));
std::memcpy(&v[size], &obj, sizeof(T));
}
Deserialization can be done similarly, there is also a choice between copying into an existing object and creating a new one.
template <typename T>
void deserialize(const std::vector<char> &v, std::size_t offset, T &obj) {
static_assert(std::is_trivially_copyable<T>::value,"Can only deserialize trivially copyable objects.");
std::memcpy(&obj, &v[offset], sizeof(T));
}
template <typename T>
T deserialize(const std::vector<char> &v, std::size_t offset) {
static_assert(std::is_trivially_copyable<T>::value,"Can only deserialize trivially copyable objects.");
T obj;
deserialize(v,offset,obj);
return obj;
}
You should get familiar with the strict aliasing rule before you do any type-casting.
Note that only trivially_copyable
types can be serialized with memcpy
and do not serialize any class with pointers. Of course none of this is compatible across machines, architectures, or compilers unless specific layout in T
is enforced.
Upvotes: 2