纪念结构变量

memcpy structure variables

本文关键字:变量 结构 纪念      更新时间:2023-10-16

这听起来很基本的问题,但是我在C 中有关注结构:

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

可以说,我有两个Smessage类型的变量(MSG1,MSG2),我想将MSG1的个体成员纳入MSG2(请不要问为什么!)。我知道复制ID和有效负载相对直接:

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

也可以工作,因为数据是一个数组对象?

我们将如何复制struct成员data2,该构件data2被声明为指针?

任何一个版本都可以使用。使用AMPERSAND(&)操作员明确地采用数组的地址,同时省略AMPERS,从而使其隐式接收数组的地址。最后,结果是相同的。

更重要的是,直接在字段上使用sizeof是更容易且易于错误的:

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

避免错别字,更重要的是,如果字段更改大小,则不必浏览您使用的代码。

至于data2,zwol在下面的答案中是正确的,因为它取决于数据的确切存储方式 - 或更准确地说,谁拥有" data2以及如何释放变量。您可能想研究"浅"与"深"复制。

您的最后两个memcpy() S应该是sizeof(msg1.data)不是100*sizeof(unsigned int)-无论如何它们是unsigned char S!

但最后一个:

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

表达式msg.data的类型与表达式&msg.data的类型不同,但是 values 是相同的。由于这是C ,因此在[conv.ptr]/2中非常清楚地指定了该行为:memcpy的调用导致两个指针参数向[const] void *的隐式转换,并且此转换的结果"指向对象属于对象的开始,如该对象所在的位置的开始如果它是最派生的对象(而不是基类子对象)"。(在C中,效果是相同的,但是标准人对这样说的不太清楚 - 您必须读取C99第6.3.2.3节第1段和第7段,并理解memcpy行为的行为一样,就好像它将其论点转换为Pointers-内部类型。)

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)上是正确的,标准仍然允许这种可能性,但是Afaik没有实施者实际上在很多年中做到了这一点。

²反驳:这将sizeof应用于阵列类型,这是有风险的,因为阵列类型"衰减"到指针类型的情况下,如果给出了丝毫的机会,则会再次默默错误。但是,如果您是手工复制结构成员的情况 - 我认为它比替代方案不那么危险。