【c++随笔29】结构体和char*转换(序列化和反序列化)
- 1. 将结构体转换为 char*(序列化)
- 2. 将 char* 转换为结构体(反序列化)
- 3. 使用 std::string 替代 char*
- 4、结构体转换为char*的其他写法
原创作者:郑同学的笔记
原文链接:https://zhengjunxue.blog.csdn.net/article/details/144650056
在 C++ 中,结构体(struct)和 char* 之间的转换通常涉及将结构体的内容序列化为一个字节流(即 char* 指针指向的内存块),或者将 char* 字节流解析回结构体。以下是两种常见的情况和解决方案:
1. 将结构体转换为 char*(序列化)
这通常是将结构体的内存内容以字节流的形式存储,便于网络传输或文件保存。
示例代码
#include<iostream>#include<cstring>// 用于 memcpy// 定义一个结构体structMyStruct{intid;floatvalue;charname[50];};intmain(){// 创建一个结构体实例MyStruct myStruct={123,45.67f,"Example"};// 将结构体内容复制到一个 char* 数组(字节流)char*buffer=newchar[sizeof(MyStruct)];std::memcpy(buffer,&myStruct,sizeof(MyStruct));// 输出字节流的内容std::cout<<"Serialized buffer content: ";for(size_t i=0;i<sizeof(MyStruct);++i){std::cout<<static_cast<int>(buffer[i])<<" ";}std::cout<<std::endl;// 释放内存delete[]buffer;return0;}- 解释:
使用 memcpy 函数将结构体的内存内容复制到一个 char* 缓冲区中。
sizeof(MyStruct) 用来获取结构体的大小,以确保拷贝足够的字节。
new char[sizeof(MyStruct)] 动态分配了内存空间来存储序列化的数据。
2. 将 char* 转换为结构体(反序列化)
反序列化是将字节流(char*)解析回结构体。你需要确保字节流的内容与目标结构体的格式完全匹配。
示例代码:
#include<iostream>#include<cstring>// 用于 memcpy// 定义一个结构体structMyStruct{intid;floatvalue;charname[50];};intmain(){// 创建一个结构体实例MyStruct myStruct={123,45.67f,"Example"};// 将结构体内容复制到一个 char* 数组(字节流)char*buffer=newchar[sizeof(MyStruct)];std::memcpy(buffer,&myStruct,sizeof(MyStruct));// 反序列化:将 char* 转换回结构体MyStruct newStruct;std::memcpy(&newStruct,buffer,sizeof(MyStruct));// 输出反序列化后的结构体内容std::cout<<"Deserialized struct: "<<std::endl;std::cout<<"id: "<<newStruct.id<<std::endl;std::cout<<"value: "<<newStruct.value<<std::endl;std::cout<<"name: "<<newStruct.name<<std::endl;// 释放内存delete[]buffer;return0;}解释:
我们再次使用 memcpy 将 char* 缓冲区中的字节数据拷贝回结构体。
std::memcpy(&newStruct, buffer, sizeof(MyStruct)) 将字节流反序列化成 MyStruct 结构体。
反序列化之后,我们可以通过结构体的成员访问数据。
3. 使用 std::string 替代 char*
现代 C++ 推荐使用 std::string 来处理字符串和字符数组,这样可以避免手动管理内存和可能的缓冲区溢出问题。如果结构体中包含字符串,你可以将 std::string 作为成员来简化管理。
示例代码:
#include<iostream>#include<string>structMyStruct{intid;floatvalue;std::string name;// 使用 std::string 代替 char[]};intmain(){// 创建一个结构体实例MyStruct myStruct={123,45.67f,"Example"};// 将结构体转换为字节流(序列化)size_t size=sizeof(myStruct.id)+sizeof(myStruct.value)+myStruct.name.size()+1;char*buffer=newchar[size];// 手动将各个成员复制到字节流memcpy(buffer,&myStruct.id,sizeof(myStruct.id));memcpy(buffer+sizeof(myStruct.id),&myStruct.value,sizeof(myStruct.value));memcpy(buffer+sizeof(myStruct.id)+sizeof(myStruct.value),myStruct.name.c_str(),myStruct.name.size()+1);// 输出序列化后的字节流内容std::cout<<"Serialized buffer content: ";for(size_t i=0;i<size;++i){std::cout<<static_cast<int>(buffer[i])<<" ";}std::cout<<std::endl;// 反序列化:从字节流恢复结构体MyStruct newStruct;memcpy(&newStruct.id,buffer,sizeof(newStruct.id));memcpy(&newStruct.value,buffer+sizeof(newStruct.id),sizeof(newStruct.value));newStruct.name=std::string(buffer+sizeof(newStruct.id)+sizeof(newStruct.value));// 输出反序列化后的结构体内容std::cout<<"Deserialized struct: "<<std::endl;std::cout<<"id: "<<newStruct.id<<std::endl;std::cout<<"value: "<<newStruct.value<<std::endl;std::cout<<"name: "<<newStruct.name<<std::endl;// 释放内存delete[]buffer;return0;}解释:
std::string 是 C++ 提供的安全字符串类,自动管理内存,因此使用它可以避免手动处理 char* 的问题。
我们依然手动进行序列化和反序列化,但 std::string 使得字符串操作更加简单和安全。
- 总结
序列化(结构体转 char*):使用 memcpy 将结构体的内存内容拷贝到一个字节数组中。
反序列化(char* 转结构体):使用 memcpy 将字节流中的内容恢复回结构体。
现代 C++ 更推荐使用 std::string 来处理字符串,避免使用低级的 char* 类型。
4、结构体转换为char*的其他写法
- 方法一:强转
- 方法二:reinterpret_cast
reinterpret_cast 是 C++ 中用于类型转换的操作符,允许在不同类型之间进行低级别的指针转换(例如,将一个结构体指针转换为 char*)。它不会对转换进行任何类型安全的检查,因此适合用于底层的指针转换。
#include<iostream>#include<cstring>// 用于 memcpy// 定义一个结构体structMyStruct{intid;floatvalue;charname[50];};intmain(){// 创建一个结构体实例MyStruct myStruct={123,45.67f,"Example"};// 将结构体内容复制到一个 char* 数组(字节流)char*buffer=newchar[sizeof(MyStruct)];std::memcpy(buffer,&myStruct,sizeof(MyStruct));// 输出字节流的内容std::cout<<"Serialized buffer content: ";for(size_t i=0;i<sizeof(MyStruct);++i){std::cout<<static_cast<int>(buffer[i])<<" ";}std::cout<<std::endl;char*buf=(char*)&myStruct;if(memcmp(buffer,buf,sizeof(MyStruct))==0)std::cout<<"buffer and buf is same\n";char*buf2=reinterpret_cast<char*>(&myStruct);if(memcmp(buffer,buf2,sizeof(MyStruct))==0)std::cout<<"buffer and buf2 is same";// 释放内存delete[]buffer;return0;}