# serialize **Repository Path**: qykhhr/serialize ## Basic Information - **Project Name**: serialize - **Description**: C++序列化 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-02-14 - **Last Updated**: 2023-03-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 介绍 ## 概念 序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。 ## 序列化的方式 1. 文本格式:JSON、XML 2. 二进制格式:protobuf ## 二进制序列化 序列化:将数据结构或对象转换成二进制串的过程。 反序列化:将在序列化过程中所产生的二进制串转换成数据结构或对象的过程。 - 序列化后,数据小,传输速度快 - 序列化、反序列化速度快 ## serialize 用法演示 ### 基本类型序列化、反序化 基本类型序列化 ```C++ int main() { DataStream ds; int n = 123; double f = 1.23; string s = "kitty"; ds << n << f << s; ds.save("a.out"); return 0; } ``` 基本类型反序列化 ```C++ int main() { DataStream ds; ds.load("a.out"); int n; double f; string s; ds >> n >> f >> s; return 0; } ``` ### 复合类型数据序列化、反序列化 ```C++ int main() { DataStream ds; std::vector v{1, 2, 3}; ds << v; ds.save("v.out"); return 0; } ``` ### 自定义类序列化、反序列化 A类 ```C++ class A : public Serializable { public: A() {} A(const string & name, int age) : m_name(name), m_age(age) {} void show() { std::cout << "name=" << m_name << ",age=" << m_age << std::endl; } SERIALIZE(m_name, m_age) private: string m_name; int m_age; }; ``` B类 ```C++ class B : public Serializable { public: B() {} void add(const A & a) { m_vector.push_back(a); } void show() { for (auto it = m_vector.begin(); it != m_vector.end(); it++) { it->show(); } } SERIALIZE(m_vector) private: std::vector m_vector; }; ``` ## Protobuf 与 serialize 的区别 | | protobuf | yazi-serialize | | ------------ | -------- | -------------- | | 二进制格式 | 是 | 是 | | 数据体积 | 小 | 小 | | 编解码速度 | 快 | 快 | | 数据类型支持 | 丰富 | 更加丰富 | | 消息定义文件 | 需要 | 不需要 | | 需要编译 | 需要 | 不需要 | | 代码实现 | 复杂 | 简单 | # 数据类型定义 ```C++ enum DataType { BOOL = 0, CHAR, INT32, INT64, FLOAT, DOUBLE, STRING, VECTOR, LIST, MAP, SET, CUSTOM }; ``` # 基本类型序列化 + 反序列化 ## 基本数据类型编码 | 字段类型 | 字段长度(字节) | 底层编码格式 | | -------- | ---------------- | --------------------------------- | | bool | 2 | Type(1) + Value(1) | | char | 2 | Type(1) + Value(1) | | int32 | 5 | Type(1) + Value(4) | | int64 | 9 | Type(1) + Value(8) | | float | 5 | Type(1) + Value(4) | | double | 9 | Type(1) + Value(8) | | string | 可变长度 | Type(1) + Length(5) + Value(变长) | # 复合类型序列化 + 反序列化 ## 复合数据类型编码 | 字段类型 | 字段长度 | 底层编码 | | --------- | -------- | ----------------------------------------------------------- | | vector | 可变长度 | Type(1) + Length(5) + Value(T + T + T + ...) | | list | 可变长度 | Type(1) + Length(5) + Value(T + T + T + ...) | | map | 可变长度 | Type(1) + Length(5) + Value((K, V) + (K, V) + (K, V) + ...) | | set | 可变长度 | Type(1) + Length(5) + Value(T + T + T + ...) | # 自定义类序列化 + 反序列化 ## 自定义对象类型编码 | 字段类型 | 字段长度 | 底层编码 | | -------- | -------- | ----------------------------------- | | 自定义类 | 可变长度 | Type(1) + Value(D1 + D2 + D3 + ...) | Serializable 接口类: ```C++ class Serializable { public: virtual void serialize(DataStream & stream) const = 0; virtual bool unserialize(DataStream & stream) = 0; }; ``` SERIALIZE 宏 ```C++ #define SERIALIZE(...) \ void serialize(DataStream & stream) const \ { \ char type = DataStream::CUSTOM; \ stream.write((char *)&type, sizeof(char)); \ stream.write_args(__VA_ARGS__); \ } \ \ bool unserialize(DataStream & stream) \ { \ char type; \ stream.read(&type, sizeof(char)); \ if (type != DataStream::CUSTOM) \ { \ return false; \ } \ stream.read_args(__VA_ARGS__); \ return true; \ } #include "Serializable.h" using namespace serialize; class A : public Serializable { public: SERIALIZE(m_name, m_age) private: string m_name; int m_age; }; ``` 如何让一个类可以序列化: 1. 继承 Serializable 接口类 2. SERIALIZE 宏定义需要序列化的字段 # 大端与小端 ## 字节序 字节顺序又称端序或尾序(Endianness),在计算机科学领域中,指电脑内存中或在数字通信链路中,组成多字节的字的字节的排列顺序。 ## 小端 Little-Endian:将低序字节存储在起始地址(低位编址),在变量指针转换的时候地址保持不变,比如 int64* 转到 int32*,对于机器计算来说更友好和自然。 ## 大端 Big-Endian:将高序字节存储在起始地址(高位编址),内存顺序和数字的书写顺序是一致的,对于人的直观思维比较容易理解,网络字节序统一规定采用 Big-Endian。 ## 检测字节序 1、系统提供的宏验证(__BYTE_ORDER) ```C++ #include #include int main(int argc, const char *argv[]) { if (__BYTE_ORDER == __LITTLE_ENDIAN) { printf("LITTLE\n"); } else if (__BYTE_ORDER == __BIG_ENDIAN) { printf("BIG\n"); } else { printf("UNKNOW\n"); } return 0; } ``` 2、通过字节存储地址判断 ```C++ #include #include int main() { int n = 0x12345678; char str[4]; memcpy(str, &n, sizeof(int)); for (int i = 0; i < sizeof(int); i++) { printf("%x\n", str[i]); } if (str[0] == 0x12) { printf("BIG\n"); } else if (str[0] == 0x78) { printf("LITTLE\n"); } else { printf("UNKNOW\n"); } return 0; } ``` 大小端枚举 ```C++ enum ByteOrder { BigEndian, LittleEndian }; ``` 检测字节序算法 ```C++ DataStream::ByteOrder DataStream::byteorder() { int n = 0x12345678; char str[4]; memcpy(str, &n, sizeof(int)); if (str[0] == 0x12) { return ByteOrder::BigEndian; } else { return ByteOrder::LittleEndian; } } ``` 反转字节序算法 ```C++ #include int value = 0x12345678; char * first = (char *)&value; char * last = first + sizeof(int); std::reverse(first, last); ```