user11472260
user11472260

Reputation:

How to convert any value to byte array and append it to a byte list?

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

My Problem

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

Answers (1)

Quimby
Quimby

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

Related Questions