memcpy 结构变量

memcpy structure variables

这听起来可能是一个非常基本的问题,但我在 C++ 中有以下结构:

struct SMessage
{
    unsigned int id; 
    unsigned int payloadSize; 
    unsigned char data[100];  
    unsigned char *data2; 
}; 

假设我有两个 SMessage 类型的变量 (msg1,msg2),我想将 msg1 的各个成员 memcpy 到 msg2(请不要问为什么!)。我知道复制 id 和 payLoadSize 相对简单:

memcpy(&msg2.id, &msg1.id, sizeof(unsigned int)); 
memcpy(&msg2.payLoadSize, &msg2.payLoadSize, sizeof(unsigned int));

但是为了复制数据[]我们应该这样做:

memcpy(&msg2.data, &msg1.data, 100*sizeof(unsigned char)); 

memcpy(msg2.data, msg2.data, 100*sizeof(unsigned int)) 

也可以,因为数据是数组对象?

我们如何复制声明为指针的结构成员data2?

表达式 msg.data 的类型与表达式 &msg.data 的类型不同,但 相同。由于这是 C++,因此 [conv.ptr]/2 中非常明确地指定了行为:对 memcpy 的调用导致两个指针参数隐式转换为 [const] void *,并且此转换的结果 "points to the start of the storage location where the object resides, as if it is a most derived object (not a base class subobject)". (在 C 中,效果是一样的,但标准语不太清楚这样说——你必须一起阅读 C99 节 6.3.2.3 第 1 段和第 7 段,并理解 memcpy 表现 "as if" 它转换它的参数在内部指向字符类型的指针。)

data 声明为

unsigned char data[100];  

因此以下所有内容都是等价且正确的。在我处理过的大多数代码库中,第一个将是首选样式。

memcpy(msg2.data, msg1.data,   sizeof msg1.data);

memcpy(msg2.data, msg1.data,   100);
memcpy(msg2.data, msg1.data,   100 * sizeof(unsigned char));

memcpy(&msg2.data, &msg1.data, sizeof msg1.data);
memcpy(&msg2.data, &msg1.data, 100);
memcpy(&msg2.data, &msg1.data, 100 * sizeof(unsigned char));

然而,

memcpy(msg2.data, msg1.data, 100 * sizeof(unsigned int));

错了;它复制了太多内存。¹ 这就是为什么带有 sizeof 的形式是首选样式的原因;一开始就更难出错,并且如果类型定义发生变化,也不会默默地出错。²

另外,作为风格问题,我不喜欢在这种情况下写 &,因为 &[anything with an array type] 几乎总是错误的,所以除非确实有必要,否则不应那样写。

你应该知道 sizeof(any sort of char) == 1 根据定义 (C++ [expr.sizeof]/1)。这是我个人但广泛认同的观点,这意味着 sizeof(char) 永远不应出现在您的代码中。

最后,如果没有更多信息,我无法告诉您正确的复制方法data2。我需要知道 data2 指向什么,它是如何分配的,是否应该复制或引用。


¹ 除了极不可能的情况 sizeof(unsigned char) == sizeof(unsigned int);这在最初的 Cray 上是正确的,并且标准仍然允许这种可能性,但是据我所知,很多很多年没有实施者真正做到这一点。

² 反驳:这是将 sizeof 应用于数组类型,这是有风险的,因为数组类型 "decay" 应用于指针类型,如果有丝毫的机会这样做,那么它又会是默默的错了。不过,在您所处的情况下 — 手动复制结构成员 — 我认为它比替代方法更不危险。

任何一个版本都可以。使用与号 (&) 运算符显式获取数组地址,而省略与号会导致它隐式获取数组地址。最后结果一样。

更重要的是,直接在字段上使用sizeof更简单,更不容易出错:

std::memcpy(msg2.data, msg1.data, sizeof(msg1.data));

这避免了拼写错误,更重要的是,如果字段大小发生变化,您不必通过代码查找您使用过它的地方。

至于 data2,zwol 在他下面的回答中是正确的,因为它取决于 data2 究竟存储了什么——或者更准确地说,谁 "owns" data2 以及变量将如何被释放。您可能想查看 "shallow" 与 "deep" 复制。

你的最后两个 memcpy() 应该是 sizeof(msg1.data) 而不是 100*sizeof(unsigned int) - 反正它们是 unsigned char

但是最后一个:

memcpy(msg2.data, msg2.data, 100*sizeof(unsigned int));

正确。如果您想使用较早的一个,请使用:

memcpy(&msg2.data[0], &msg1.data[0], 100*sizeof(unsigned int)); 

两者都是错误的,因为如果sizeof(unsigned int)大于sizeof(char),它们将导致越界访问。

您可以执行以下任一操作

memcpy(&msg2.data, &msg1.data, sizeof(msg1.data)); // pass pointers to arrays
memcpy(msg2.data, msg1.data, 100*sizeof(unsigned char)); // pass pointers to first elements of the arrays