使用memcpy

时间:2017-11-29 12:21:36

标签: c

我有以下结构:

 typedef struct P{
     int age;
     char gender;
     int weight;
 }Person;

我正在处理数据块。所以我的所有数据都在char Person_Data[50];

之内

预期结果是将数据从Person_Data移动到我的结构。为了达到这个目的,我使用memcpy,记住在Person_Data内我可以存储int或char(或者我可能添加的任何其他内容)。

我为可测试的例子编写了一个代码:

char Person_Data[50];
size_t offset = 0;
memset(Person_Data + offset, 24, sizeof(int));
offset += sizeof(int);
memset(Person_Data + offset, 'M', sizeof(char));
offset += sizeof(char);
memset(Person_Data + offset, 55, sizeof(int));

printf("Age = %d, Gender = %c, weight = %d\n", *(Person_Data), *(Person_Data +  sizeof(int)), *(Person_Data + sizeof(int) + sizeof(char)));

在此之前,我们可以看到我的字符串中的数据正确传递,并保持其类型。 (我想从我在各种书中读过的内容)。

现在我将数据从Person_Data传递给我的struct:

Person *Person1 = malloc(sizeof(Person));
offset = 0;
memcpy(&Person1->age, Person_Data + offset, sizeof(int));
offset += sizeof(int);
memcpy(&Person1->gender, Person_Data + offset, sizeof(char));
offset += sizeof(char);
memcpy(&Person1->weight, Person_Data + offset, sizeof(int));

printf("Age = %d, Gender = %c, weight = %d\n", Person1->age, Person1->gender, Person1->weight);

正如我们所看到的,上面代码的输出是

Age = 24, Gender = M, weight = 55
Age = 404232216, Gender = M, weight = 926365495

因此,2 int未正确传递到结构中。

这让我感到疑惑,我用这样的memset尝试了这个:

memset(&Person1->age, *(Person_Data + offset), sizeof(int));

但它也没有奏效。所以最后的尝试是像这样传递int:

Person1->age = *(Person_Data);

这样做后,我看到年龄已正确通过。 我的想法是这是否正确。

" ="运算符知道要传递多少字节?

不应该记得memcpy / memset,因为第三个参数是要复制多少字节?

谢谢。

2 个答案:

答案 0 :(得分:9)

无论你想做什么,都不要这样做。

+--+--+--+--+--+--+--+--+--+--+--+--+
|18|18|18|18| M|37|37|37|37|xx|xx|xx| 
+--+--+--+--+--+--+--+--+--+--+--+--+
 \   int   /char\  pad / \   int   / 

这将创建以下内存布局(假设int为32位):

printf("Age = %d, Gender = %c, weight = %d\n", *(Person_Data), *(Person_Data + sizeof(int)), *(Person_Data + sizeof(int) + sizeof(char)));

您复制到错误的位置。

为什么打印似乎有效? 因为你不打印int值但只打印char。

int

从内存中读取单个字符值,并在传递给printf之前将其提升为offsetof

作为一般规则:

  • 不要计算偏移量,但请使用评论中已建议的memset
  • 请勿使用char填充整数。
  • 如果您想使用结构,请不要使用"hapi": "^16.6.2", "inert": "^4.2.1", 数组。

答案 1 :(得分:5)

memset不是用于设置除字符数组或字节数之外的对象的值。 memset使用相同的值填充目标的每个字节。当您使用memset(destination, 24, sizeof(int))时,您将使用值24填充每个字节。这些组合字节会产生一个非常大的整数值。

虽然您使用大整数填充age字段,但您在printf中看不到它,因为您使用printf将值传递给*(Person_data)。由于Person_data是指向char的指针,因此该表达式仅从对象中提取一个字符,因此它只获取包含24的字节之一。相反,当您使用Person1->age时,ageint,因此会提取整个int

此外,您不应该假设您可以简单地在结构中添加对象的大小以获取成员的地址。大多数硬件体系结构都具有数据的对齐要求,这意味着多个字节的对象必须从其大小的倍数或诸如两个,四个或八个字节的值的内存地址开始。当您在其中声明具有不同对象类型的结构时,编译器会在它们之间包含一些未使用的空间以使对齐正确。 offsetof标题中有一个<stddef.h>宏,它将为您提供结构中成员的偏移量。 (我假设这段代码仅用于探索C的工作原理而不是用于真实产品。如果它用于真实产品,那么这是非常糟糕的代码。)

赋值运算符=知道要移动多少字节,因为编译器知道左操作数的类型(因为您之前在源代码中声明了类型)。

如果您确实希望通过写入其各个字节将int设置为24,则必须将24放在其低值字节中,将0放在其他字节中。但是,哪个字节是低值字节因系统而异。一些硬件架构将低值字节置于低地址,有些则将其置于高地址。 (并且,如果要将int设置为大于适合字节的值,则必须将其分成多个字节并写入。)