使用数据缓冲区而不违反严格别名

时间:2015-09-25 14:58:17

标签: c++

我想重写一段(旧)代码以符合标准。旧代码使用缓冲区来存储POD结构和校验和,以通过网络发送它并接收它。对于发送,代码如下:

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

如何更新此代码以使其完全符合标准投诉,尤其是不违反严格的别名规则?

我找到了解决类似问题的帖子:strict aliasing and alignmentShared memory buffers in C++ without violating strict aliasing rules。然而,这些都没有真正回答我的问题;或许他们这样做,但后来我没有看到它。

更新:正如一些答案已经说明的那样,最简单的方法是使用memcpy。我想知道,有没有办法使用placement new或其他构造来消除复制和构建就地的需要?

4 个答案:

答案 0 :(得分:2)

在您的情况下,避免违反严格别名规则的最简单方法是将memcpy()填充到缓冲区中。

答案 1 :(得分:1)

使用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));

答案 2 :(得分:1)

首先,您将结构的内存中表示形式发送到不同计算机的方法存在缺陷,因为其他计算机可能具有与您的不同的布局或大小。使用正确定义的元格式,如JSON,XML或类似的东西。

现在,如果你不关心这些缺陷,你可以采取更进一步的方法:

struct MessageStructWithChecksum:
    MessageStruct
{
    uint32_t checksum;
};

struct和原始字节之间的转换外,没有别名问题。另请注意,您可以定义函数本地结构,并且可以编写模板以用于不同的消息类型。

答案 3 :(得分:1)

发送部分最简单:

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

您可以通过[..] char或unsigned char类型访问对象的存储值。

对于阅读部分,我认为您必须复制以避免严格的别名规则。

但事实上,你必须做一些特殊的处理才能管理字节序(以及具有不同表现形式的类型),无论如何这都是一种复制。

相关问题