我是c和cpp的新手,我想知道是否有一种方法可以将char * buffer转换为struct,考虑到它可以在字节数组中容纳多个0x 00。我有一个结构头,我包括在我的cpp文件。
struct ExampleStruct{
uint8_t id;
uint16_t message;
int8_t param1;
int16_t param2;
int8_t param3;
int8_t param4;
}
在我的cpp文件中,我有一个udp服务器,它在char * buffer中接收N个字节;缓冲区可能看起来像这样:
char buffer[] = {0x0f, 0xff, 0x00, 0xd4, 0xff, 0x00, 0x00, 0xff};
我试着这样做:
struct ExampleStruct exampleStruct;
memcpy(&exampleStruct, buffer, bytesReceived);
还有这个
struct ExampleStruct *exampleStruct = (ExampleStrcut *)buffer;
,但是当我尝试以十六进制输出例如exampleStruct.param4时,它们都不起作用,它显示了其他内容。另外,我无法控制缓冲区消息的发送。
我怎么把它转换成一个结构体呢,我试着把它强制转换,但是由于某种原因,它强制转换不正确,我觉得这可能是由于字节数组中有0x 00。请帮我把它转换成收到的N字节
3条答案
按热度按时间wsewodh21#
恕我直言,更安全的方法是逐个字段或逐个成员复制。此技术允许您插入成员的转换(例如小端到大端)。
这消除了结构中的填充问题,因此不需要非标准的
pack
杂注。(Note:因为OP标记了C++,所以我使用了成员函数。)
由于选择了 C++ 标记,因此可以轻松地将其调整为简单的序列化接口:
通过按引用传递缓冲区指针,您可以通过传递相同的指针来“链接”调用。这允许在
struct
或class
中轻松集成非POD成员。size_in_buffer
方法用于分配目标缓冲区,因为缓冲区的大小可能与结构的大小不同(由于填充、对齐等原因)。f2uvfpb92#
为了在可移植代码中实现这一点,通常必须显式地处理转换,一次一个,并且通常希望将原始数据读入
unsigned char
数组,以便可以轻松/安全地使用它进行位游戏。当我做这样的事情时,我通常定义一个
byte
类,以便于将字节写成无符号数(uint8_t
通常是unsigned char
的别名,因此它们会打印为字符)。我还定义了一个小模板函数来从字节流中读取大端整数。
对于这个结构体来说,这可能有点大材小用,但是如果您正在进行网络通信,您可能最终会使用它们的更多用途。
把这些放在一起,代码看起来像这样:
结果:
(这似乎是我所期望的)。
当然,如果您的
uint16_t
项是little-endian(对于网络数据来说不常见,但肯定是可能的),则可以使用LittleEdian<uint16_t>
(这显然会以little-endian顺序处理字节)。ddhy6vgd3#
有两件事可以阻止memcpy解决方案的工作。
1.对齐和填充。每个
uint16_t
地址必须能被2整除(在大多数情况下),因此C++为结构体添加了填充,使每个uint16_t
字段对齐2个字节:为了避免这种情况,你可以打包你的struct:
请注意,我使用
sizeof(ExampleStruct)
是因为您可能会收到比结构体中更多的字节,在这种情况下,您将以将不受信任的数据复制到堆栈中结束,这可能导致严重的漏洞,如远程代码执行。第二个例子在C中是不允许的,因为C标准没有定义类型双关。
1.考虑编码数据时使用的字节序。这是很有可能的,它是在编码的消息,但您的计算机有小端整数,所以每个整数值将有字节反转。