Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在不违反严格别名的情况下使用数据缓冲区_C++ - Fatal编程技术网

C++ 在不违反严格别名的情况下使用数据缓冲区

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

我想重写一段(旧的)代码以符合标准。旧代码使用缓冲区存储POD结构,并使用校验和通过网络发送和接收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)));
对于接收,代码如下所示:

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是的,这是真的,但幸运的是,现在这不是一个问题。