我有一个程序来处理char []缓冲区以发送/接收消息。到目前为止,这是如何处理的:
#pramga pack(1)
struct messageType
{
uint8_t data0:4;
uint8_t data1:4;
uint8_t data2;
//etc...
};
#pragma pack()
void MyClass::processMessage(char* buf)
{
// I already know buf is big enough to hold a messageType
messageType* msg = reinterpret_cast<messageType*>(buf);
//populate class member variables
m_data0 = msg->data0;
m_data1 = msg->data1;
m_data2 = msg->data2;
//etc
}
现在我从阅读中收集到的是,由于严格的别名,这是技术上未定义的行为,应该使用memcpy
吗?我不太明白的是,将buf
字节字节复制到messageType msgNotPtr
,然后从那个msgNotPtr
读取,实际上避免了哪些潜在问题?
关于发送,而不是这样做:
void MyClass::sendMessage()
{
char buf[max_tx_size];
messageType* msg = reinterpret_cast<messageType*>(buf);
msg->data0 = m_data0;
//etc...
send(buf);
}
我已经读过我应该使用的placement new
isntead,ala:
messageType* msg = new(buf) messageType;
如果我这样做,我是否需要添加额外的清理,因为struct messageType
只包含POD类型(例如手动触发析构函数)?
编辑:现在我想一想,sendMessage
仍未定义吗?我是否还需要使用send(reinterpret_cast<char*>(msg))
等替换最后一个命令以确保编译器不优化调用?
答案 0 :(得分:0)
在我看来,从uint8_t缓冲区加载类实例的正确方法是分别加载每个成员。
类应该知道缓冲区内成员的位置以及任何填充或保留区域的大小和位置。
将结构映射到缓冲区的一个问题是编译器可以在成员之间添加空间。如果打包结构以消除填充,则每次访问成员时都会降低程序的速度。
因此,通过将成员放在缓冲区中的所需位置(或根据规范提取成员)来确定输入和输出的性能。程序的其余部分可以按照编译器对齐的方式访问成员。
这包括位字段。
此外,通过单独加载成员,缓冲区中字段的Endianess可以更容易地解决。