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
这听起来可能是一个非常基本的问题,但我在 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