简体   繁体   English

应该始终使用memcpy吗?

[英]Should memcpy always be used?

I was working with C and manual memory management and playing around with my code and I noticed this: 我正在使用C和手动内存管理并玩我的代码,我注意到了这一点:

Suppose I had 假设我有

int *a = malloc(sizeof(int));
int *b = malloc(sizeof(int));
int c = 10;

If I take these numbers and do this: 如果我拿这些数字并执行此操作:

*a = c;

Then a will point to a distinct location in memory separate from c but will have the value of c . 然后a将指向与c分开的内存中的不同位置,但将具有c的值。 If I used: 如果我用过:

memcpy(a, &c, sizeof(int)); 

The same thing would happen. 同样的事情会发生。 Distinct pointer, same value. 不同的指针,相同的值。

My question is whether one is preferable to the other? 我的问题是,一个人是否比另一个更好? I know for char * usually it is memcpy or strcpy that is used but what about for ints? 我知道char *通常是memcpystrcpy使用但是对于int来说呢? What about pointers in general? 一般指针怎么样? Is assignment ever ok? 作业一切顺利吗?

PS I also know that PS我也知道

a = &c;

will make a point to the same memory location as c and therefore have its value but I would imagine that would leave a hanging pointer where a was since free is never called on the memory for a so I wouldn't use that. a指向同一个内存位置的c ,所以有它的价值,但我猜想,会留下悬挂指针,其中a是因为free的内存绝不会为a所以我不会使用。

In your example, you should use *a = c; 在您的示例中,您应该使用*a = c; since you only want to copy a single value. 因为你只想复制一个值。 Use memcpy , if you need to copy several consecutive elements of an array. 如果需要复制数组的多个连续元素,请使用memcpy

It is implementation specific. 它是特定于实现的。 Some compilers, including GCC , are able to optimize quite well (with gcc -O2 at least), calls to standard functions memcpy and to memset (which, as my former colleague Pascal Cuoq commented, may be inlined to efficient assignment machine code); 一些编译器,包括GCC ,能够很好地优化(至少使用gcc -O2 ),调用标准函数memcpymemset (正如我以前的同事Pascal Cuoq评论的那样,可以内联到高效的赋值机器代码); sometimes, GCC is even able to optimize some assignment to some structures as calls to memcpy (sometimes, calling an efficient memcpy routine is faster for large enough struct , including for structure assignment; at other occasions, the call to memcpy , transformed via some __builtin_memcpy , is inlined as an efficient assignment code, perhaps even going thru registers without using any memory) 有时,GCC甚至可以优化对某些结构的一些赋值,因为对memcpy调用(有时,对于足够大的struct调用高效的memcpy例程更快,包括结构赋值;在其他情况下,调用memcpy ,通过一些__builtin_memcpy转换,内联作为一个有效的赋值代码,甚至可以通过寄存器而不使用任何内存)

You could compile your foo.c example with gcc -fverbose-asm -O2 -march=native -S foo.c then look into the generated foo.s 您可以使用gcc -fverbose-asm -O2 -march=native -S foo.c编译您的foo.c示例,然后查看生成的foo.s

So if you use a recent GCC or Clang/LLVM compiler (or some other good compiler) with optimizations enabled , you should use memcpy and memset ... 因此,如果您使用最近 启用优化的 GCCClang / LLVM编译器(或其他一些好的编译器),您应该使用memcpymemset ...

In other words, memcpy(a, &c, sizeof(int)); 换句话说, memcpy(a, &c, sizeof(int)); can be optimized as efficiently as *a = c; 可以像*a = c;一样有效地进行优化*a = c; (and if you define a "type generic" macro eg using _Generic from C99, you would use memcpy and it should be optimized efficiently). (如果您定义了“类型通用”宏,例如使用C99中的_Generic ,您将使用memcpy并且应该有效地优化它)。

Should memcpy always be used? 应该始终使用memcpy吗?

Plain and simple, no . 简单, 没有

Your first goal in writing code is to make it understandable and maintainable. 编写代码的第一个目标是使其易于理解和维护。 Everyone knows what *a = c will do when a is declared as a pointer to an int and c is declared as an int. a被声明为指向int的指针并且c被声明为int时,每个人都知道*a = c会做什么。 The compiler also knows exactly what you mean by that. 编译器也确切地知道你的意思。 You'll never see a compiler optimize your *a = c to a call to memcpy because that would be a disoptimization. 你永远不会看到编译器优化你的*a = c来调用memcpy因为那将是一种不优化。

You will see the compiler optimize *a=c to a call to memcpy when c is of type struct AVeryLargeStruct and a is a pointer to the same. c的类型为struct AVeryLargeStructa是指向它的指针时,您将看到编译器优化*a=c来调用memcpy There's no need to convert *a=c to memcpy(a,&c, sizeof(c)) because the compiler does that for you, a gratis . 没有必要将*a=c转换为memcpy(a,&c, sizeof(c))因为编译器会为你做这件事免费提供 Write *a=c because that is clearer than and less error prone than is the memcpy . *a=c因为它比memcpy更清晰,更不容易出错。

There are a few places where you truly do need to use memcpy (or memmove ): 有几个地方你确实需要使用memcpy (或memmove ):

  • Copying an array, 复制数组,
  • Type punning, without using unions, and 打字,不使用工会,和
  • Copying to or from improperly aligned memory. 复制到不正确对齐的内存或从中取出。

The first is standard operating procedure; 第一是标准操作程序; no one will be shocked on reading your code and seeing a call to memcpy when used in that context. 在上下文中使用时,没有人会因为阅读您的代码并看到对memcpy的调用而感到震惊。 The latter two are not SOP. 后两者不是SOP。 Usages of memcpy in that context will give readers of your code pause. 在该上下文中memcpy用法将使读者暂停代码。 That's a good thing because you are doing something a bit tricky there. 这是一件好事,因为你在那里做了一些有点棘手的事情。 Hiding those tricky calls to memcpy amongst thousands of other calls to memcpy where you could have used ordinary assignment makes those few places where you absolutely do need to use memcpy not stand out. 隐藏那些棘手的调用memcpy当中成千上万的其他电话给memcpy ,你也可以使用普通的分配,使那几个地方,你绝对需要使用memcpy不会脱颖而出。 That's a good thing only if your goal is to win the IOCCC. 只有你的目标是赢得IOCCC,这才是一件好事。

If you use memcpy everywhere you are likely to make your code slower and you are even more likely to make others think there's something wrong with your code. 如果你在任何地方使用memcpy ,你可能会使代码变慢,你甚至更有可能让别人认为你的代码有问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM