使用赋值而不是memcpy()在C中复制结构

oll*_*zhu 21 c struct pointers memcpy

直到最近,我才看到复制完成的结构字段memcpy().在类和在线指令中,将一个结构的内容复制到另一个结构中通常看起来像

struct block *b0 = malloc(sizeof(struct block));
struct block *b1 = malloc(sizeof(struct block));
/* populate fields in *b0 */
memcpy(b1, b0, sizeof *b1); /* copy contents of b0 into b1 */
/* free b0, b1 */
Run Code Online (Sandbox Code Playgroud)

但是,这个任务也可以通过简单的分配来替换memcpy().

*b1 = *b0; /* dereferenced struct assignment */
Run Code Online (Sandbox Code Playgroud)

有没有充分的理由说明为什么它没有被广泛使用(至少在我有限的经验中)?这两种方法是分配和memcpy()等价的,还是有一些令人信服的理由memcpy()一般使用?

bdo*_*lan 29

两种方法都是等效的,并执行浅拷贝.这意味着复制了结构本身,但不复制结构引用的任何内容.

至于为什么memcpy更受欢迎,我不确定.较旧版本的C不支持结构分配(虽然它早在1978年就是常见的扩展),因此memcpy样式可能会成为制作更多可移植代码的方式吗?在任何情况下,结构分配在PC编译器中得到广泛支持,并且使用memcpy更容易出错(如果大小错误,可能会发生坏事),因此最好尽可能使用结构分配.

但是,有些情况只能memcpy起作用.例如:

  • 如果要将结构复制到未对齐的缓冲区或从未对齐的缓冲区复制 - 例如,要保存/加载到磁盘或从网络发送/接收 - 您需要使用memcpy,因为结构分配需要正确对齐源和目标.
  • 如果要在结构之后打包附加信息(可能使用零元素数组),则需要使用memcpy,并将此附加信息计入大小字段.
  • 如果要复制结构数组,则单独执行单个而不是循环和复制结构可能更有效memcpy.然后,它可能不会.很难说,memcpy实现的性能特征不同.
  • 某些嵌入式编译器可能不支持结构分配.当然,有问题的编译器可能还不支持其他更重要的事情.

还要注意,虽然在C memcpy和结构赋值中通常是等价的,但在C++ memcpy和结构赋值中并不等价.在一般的C++中,最好避免使用memcpy结构,因为结构分配可以并且经常被重载以执行其他操作,例如深层复制或引用计数管理.


Jey*_*ram 6

这可能不是您寻找的确切答案.

我解释了我遇到的情景.

当我们使用memcpy()它时,它会逐字节地复制到目标.所以不用担心ARM架构中的数据对齐.如果使用=运算符,并且任何一个地址未与4字节对齐,则会出现对齐故障.

来自Arm站点:

指向目标位置的指针,该指针位于写入的最后一个字节之外一个字节.这使得能够继续with perfect alignment of bytes用于字符串串联内存块的写入过程.

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0175k/Cihbbjge.html

  • 编译器不应该处理正确对齐的所有内容吗? (2认同)
  • @alk,编译器假定所有内容都正确对齐,因为这可以在许多平台上实现显着的性能提升.如果你只是使用malloc为你的结构分配内存,它将确保它是对齐的,但如果你开始做指针算术或从文件或网络中读取结构,则不再是这种情况,并且编译器的假设可能会被违反,导致未定义行为.请注意,您不会在x86上看到这一点,因为大多数x86操作都会透明地处理未对齐的访问,性能会略有下降. (2认同)

Fré*_*hal 6

我重新提出这个老问题是因为答案并没有解释为什么 memcpy实际上是首选的。

memcpy是首选,因为它清楚地表明程序员想要复制内容而不仅仅是指针。

在下面的示例中,两个赋值产生了两个截然不同的结果:

struct Type *s1,*s2;
*s1=*s2;
s1=s2;
Run Code Online (Sandbox Code Playgroud)

无意中使用其中一种而不是另一种可能会产生灾难性的影响。编译器不会抱怨。除非程序在使用未初始化的指针时崩溃,否则该错误可能会在很长一段时间内被忽视并产生奇怪的副作用。

将其写为以下之一:

memcpy(s1,s2,sizeof(*s1));
memcpy(s1,s2,sizeof(*s2));
memcpy(s1,s2,sizeof(struct Type));
Run Code Online (Sandbox Code Playgroud)

让读者知道其意图是复制内容(以牺牲类型安全和边界检查为代价)。

一些编译器(例如 gcc)甚至在遇到类似以下情况时发出有关 sizeof 的警告:

memcpy(s1,s2,sizeof(s1));
Run Code Online (Sandbox Code Playgroud)