C++ 在不违反严格别名的情况下使用数据缓冲区
我想重写一段(旧的)代码以符合标准。旧代码使用缓冲区存储POD结构,并使用校验和通过网络发送和接收POD结构。对于发送,代码如下所示:C++ 在不违反严格别名的情况下使用数据缓冲区,c++,C++,我想重写一段(旧的)代码以符合标准。旧代码使用缓冲区存储POD结构,并使用校验和通过网络发送和接收POD结构。对于发送,代码如下所示: struct MessageStruct {int a; float b;}; char buffer[sizeof(MessageStruct) + sizeof(uint32_t)]; ((MessageStruct*)buffer)->a = 12; ((MessageStruct*)buffer)->b = 3.14159f; *((uin
struct MessageStruct {int a; float b;};
char buffer[sizeof(MessageStruct) + sizeof(uint32_t)];
((MessageStruct*)buffer)->a = 12;
((MessageStruct*)buffer)->b = 3.14159f;
*((uint32_t*)(buffer + sizeof(MessageStruct))) = 9876;
// Use the data buffer in some way.
SendMessage(buffer, sizeof(buffer));
struct MessageStruct {int a; float b;};
// Receive: char *buffer, int size
const MessageStruct *message = (MessageStruct*)buffer;
uint32_t checksum = *((uint32_t*)(buffer + sizeof(MessageStruct)));
对于接收,代码如下所示:
struct MessageStruct {int a; float b;};
char buffer[sizeof(MessageStruct) + sizeof(uint32_t)];
((MessageStruct*)buffer)->a = 12;
((MessageStruct*)buffer)->b = 3.14159f;
*((uint32_t*)(buffer + sizeof(MessageStruct))) = 9876;
// Use the data buffer in some way.
SendMessage(buffer, sizeof(buffer));
struct MessageStruct {int a; float b;};
// Receive: char *buffer, int size
const MessageStruct *message = (MessageStruct*)buffer;
uint32_t checksum = *((uint32_t*)(buffer + sizeof(MessageStruct)));
如何更新此代码以使其完全符合标准,尤其是不违反严格的别名规则
我发现一些帖子也提到了类似的问题:。然而,这些都不能真正回答我的问题;也许他们会,但我看不到
更新:如一些答案所述,最简单的方法是使用
memcpy
。我想知道,有没有办法使用placement new或另一种不需要复制的构造来实现这一点?在您的情况下,避免违反严格别名规则的最简单方法是将memcpy()填充到缓冲区中。在您的情况下,避免违反严格别名规则的最简单方法是将memcpy()放入缓冲区。使用memcpy
:
MessageStruct msg;
msg.a = 12;
msg.b = 3.14;
uint32_t n = 9876;
memcpy(buffer, &msg, sizeof(msg));
memcpy(buffer + sizeof(msg), &n, sizeof(n));
使用
memcpy
:
MessageStruct msg;
msg.a = 12;
msg.b = 3.14;
uint32_t n = 9876;
memcpy(buffer, &msg, sizeof(msg));
memcpy(buffer + sizeof(msg), &n, sizeof(n));
首先,您将结构的内存表示形式发送到另一台机器的方法是有缺陷的,因为另一台机器的布局甚至大小可能与您的不同。使用正确定义的元格式,如JSON、XML等 现在,如果您不在乎这些缺陷,您可以进一步采取自己的方法:
struct MessageStructWithChecksum:
MessageStruct
{
uint32_t checksum;
};
除了
struct
和原始字节之间的转换之外,没有别名问题。还要注意的是,您可以定义函数本地结构,并且可以编写用于不同消息类型的模板。首先,您将结构的内存表示发送到不同机器的方法是有缺陷的,因为另一台机器的布局甚至大小可能与您的不同。使用正确定义的元格式,如JSON、XML等
现在,如果您不在乎这些缺陷,您可以进一步采取自己的方法:
struct MessageStructWithChecksum:
MessageStruct
{
uint32_t checksum;
};
除了struct
和原始字节之间的转换之外,没有别名问题。还请注意,您可以定义函数本地结构,并且可以编写一个用于不同消息类型的模板。发送部分最简单:
struct MessageStruct {int a; float b;};
struct MessageStructWithCheckSum { MessageStruct s; uint32_t check_sum;};
MessageStructWithCheckSum m;
m.s.a = 12;
m.s.b = 3.14159f;
m.check_sum = 9876;
// Use the data buffer in some way.
SendMessage(reinterpret_cast<const unsigned char*>(m), sizeof(m));
struct MessageStruct{inta;float b;};
结构MessageStructWithCheckSum{MessageStruct s;uint32\u t check\u sum;};
带校验和m的messagestruct;
m、 s.a=12;
m、 s.b=3.14159f;
m、 校验和=9876;
//以某种方式使用数据缓冲区。
SendMessage(重新解释铸造(m),尺寸(m));
您可以通过[…]字符或无符号字符类型访问对象的存储值
对于阅读部分,我认为您必须复制以避免严格的别名规则
但事实上,您必须进行特殊处理来管理endianness(以及具有不同表示形式的类型),这是一种拷贝。发送部分最简单:
struct MessageStruct {int a; float b;};
struct MessageStructWithCheckSum { MessageStruct s; uint32_t check_sum;};
MessageStructWithCheckSum m;
m.s.a = 12;
m.s.b = 3.14159f;
m.check_sum = 9876;
// Use the data buffer in some way.
SendMessage(reinterpret_cast<const unsigned char*>(m), sizeof(m));
struct MessageStruct{inta;float b;};
结构MessageStructWithCheckSum{MessageStruct s;uint32\u t check\u sum;};
带校验和m的messagestruct;
m、 s.a=12;
m、 s.b=3.14159f;
m、 校验和=9876;
//以某种方式使用数据缓冲区。
SendMessage(重新解释铸造(m),尺寸(m));
您可以通过[…]字符或无符号字符类型访问对象的存储值
对于阅读部分,我认为您必须复制以避免严格的别名规则
但事实上,您必须进行特殊处理来管理endianness(以及具有不同表示形式的类型),这是一种复制。感谢您的快速回答。我也在考虑这个解决方案,但我也希望有一个避免复制的解决方案。没有标准的方法。有些人会建议基于工会的解决方案,但从技术上来说,这仍然是UB——尽管这不是一个可能会打击到你的解决方案。谢谢你快速的回答。我也在考虑这个解决方案,但我也希望有一个避免复制的解决方案。没有标准的方法。有些人会建议基于工会的解决方案,但从技术上讲,这仍然是UB——尽管这不是一个可能会让你感到惊讶的解决方案。IIANM,语言律师标签主要用于正式的标准问题,而不是实际问题。@jrok-Hmm,说得好。我会删除它。顺便说一句,你可能有耐力problem@Jarod42是的,这是真的,但幸运的是,现在这不是一个问题。IIANM,语言律师标签主要用于正式的标准问题,而不是实际问题。@jrok-Hmm,说得好。我会删除它。顺便说一句,你可能有耐力problem@Jarod42是的,这是真的,但幸运的是,现在这不是一个问题。