¿Cuál es la diferencia entre memmove
y memcpy
? ¿Cuál usas habitualmente y cómo?¿Cuál es la diferencia entre memmove y memcpy?
Respuesta
Con memcpy
, el destino no puede superponerse a la fuente en absoluto. Con memmove
puede. Esto significa que memmove
podría ser un poco más lento que memcpy
, ya que no puede hacer las mismas suposiciones. Por ejemplo, memcpy
siempre copia direcciones de menor a mayor. Si el destino se superpone después de la fuente, esto significa que algunas direcciones se sobrescribirán antes de copiarse. memmove
detectaría esto y copiaría en la otra dirección, de mayor a menor, en este caso. Sin embargo, comprobar esto y cambiar a otro algoritmo (posiblemente menos eficiente) lleva tiempo.
cuando se usa memcpy, ¿cómo puedo garantizar que las direcciones src y dest no se superpongan? ¿Debo personalmente asegurarme de que src y dest no se superpongan? – Alcott
@Alcott, no use memcpy si no sabe que no se superponen: use memmove en su lugar. Cuando no hay superposición, memmove y memcpy son equivalentes (aunque memcpy puede ser muy, muy, muy rápido). – bdonlan
Puede usar la palabra clave 'restringir' si está trabajando con arreglos largos y desea proteger su proceso de copiado. Por ejemplo, si su método toma como parámetros matrices de entrada y salida, y debe verificar que el usuario no pase la misma dirección como entrada y salida. Lea más aquí http://stackoverflow.com/questions/776283/what-does-the-restrict-keyword-mean-in-c – DanielHsH
Uno maneja los destinos superpuestos y el otro no.
memmove
puede manejar la superposición de memoria, memcpy
no puede.
Considere
char[] str = "foo-bar";
memcpy(&str[3],&str[4],4); //might blow up
Obviamente, el origen y el destino ahora se superponen, estamos sobrescribiendo "-bar" con la "barra". Es un comportamiento indefinido usando memcpy
si la fuente y el destino se superponen, por lo que en este caso necesitamos memmove
.
memmove(&str[3],&str[4],4); //fine
¿por qué primero explotaría? –
@ultraman: Porque PUEDE haberse implementado usando assembley de bajo nivel que requiere que la memoria no se superponga. Si lo hace, podría, por ejemplo, generar una señal o una excepción de hardware para el procesador que aborta la aplicación. La documentación especifica que no maneja la condición, pero el estándar no especifica qué sucederá cuando estas condiciones estén cargadas (esto se conoce como comportamiento indefinido). El comportamiento indefinido puede hacer cualquier cosa. –
con gcc 4.8.2, incluso memcpy también acepta la superposición de punteros de origen y destino y funciona bien. – JagsVG
La diferencia técnica se ha documentado bastante bien en las respuestas anteriores. Las diferencias prácticas también deben tenerse en cuenta:
Memcpy necesitará aproximadamente el doble de la cantidad de memoria para realizar la misma tarea, pero el memmove podría tomar mucho más tiempo que memcpy.
Ejemplo:
Digamos que usted tiene una lista de 100 elementos en la memoria, teniendo 100 MB de memoria. Ahora desea descartar la primera partida por lo que sólo tiene 99.
establecimiento de memoria requerirá la original de 100 MB y un adicional de 99 MB para su nueva lista de 99 artículos. Aproximadamente 199 MB en total para realizar la operación, pero debe ser muy rápido.
Memmove, en el peor de los casos, requerirá los 100 MB originales y moverá cada elemento 1 de la dirección de memoria a la vez. Esto solo requiere los 100 MB originales, pero será significativamente más lento que Memcpy.
Por supuesto, crear un nuevo puntero para apuntar al segundo elemento de su lista logrará el mismo efecto de "soltar" el primer elemento de su lista, pero el ejemplo muestra las diferencias en memcpy y memmove.
- EDITAR para ayudar a aclarar MI RESPUESTA CRAPPY -
Sí, las implementaciones de memcpy() y memmove() probablemente no difieren en el uso de memoria (que realmente no saben), pero ¿cómo se utiliza ellos afectarán enormemente el uso de la memoria de su programa. Eso es lo que quise decir con las diferencias prácticas de memcpy() y memmove().
int SIZE = 100;
Item *ptr_item = (Item *) malloc(size_of(Item) * SIZE);
Item *ptr_src_item = ptr_item + 1;
Item *ptr_dst_item = ptr_item;
memmove(ptr_dst_item, ptr_src_item, SIZE - 1);
Esto crea su lista de elementos con el primer elemento faltante. Esto esencialmente no requiere más memoria para su programa que lo que se necesita para asignar el bloque de memoria ptr_item original. No puede hacer esto usando memcpy() ... si lo hiciera, su programa necesitaría asignar aproximadamente el doble de memoria.
int SIZE = 100;
Item *ptr_src_item = (Item *) malloc(size_of(Item) * SIZE);
Item *ptr_dst_item = (Item *) malloc(size_of(Item) * (SIZE - 1));
memcpy(ptr_dst_item, ptr_src_item, SIZE - 1);
En este segundo bloque de código, el programa requerirá el doble de memoria que el primer bloque. Sin embargo, este segundo bloque debe funcionar significativamente más rápido que el primer bloque, especialmente a medida que aumenta TAMAÑO.
Así es como yo estaba tratando de explicar las diferencias prácticas en los dos ... pero ¿tal vez estoy equivocado con esto también?
Tiene memcpy y memmove mezclados; tampoco requiere memoria extra más allá de un mínimo de espacio de pila. memmove comprueba si la fuente tiene una dirección inferior a la del destino; si es así, copia desde el final hacia atrás; si no, copia desde el principio hacia adelante. No se necesitan almacenamientos intermedios temporales. –
Debería haber vuelto a escribir su respuesta en lugar de tener básicamente dos partes conflictivas y confusas de su publicación, una en la que es bastante inflexible sobre _ "el doble de la cantidad de memoria" _ y más adelante donde _ _ "probablemente no difieren en el uso de memoria (realmente no lo sé) "_. Decídase o al menos investigue antes – MickyD
La principal diferencia entre memmove()
y memcpy()
es que en memmove()
un búfer - memoria temporal - se utiliza, por lo que no hay riesgo de solapamiento. Por otro lado, memcpy()
copia directamente los datos de la ubicación que apunta la fuente a la ubicación señalada por el destino . (http://www.cplusplus.com/reference/cstring/memcpy/)
Considere los siguientes ejemplos:
#include <stdio.h> #include <string.h> int main (void) { char string [] = "stackoverflow"; char *first, *second; first = string; second = string; puts(string); memcpy(first+5, first, 5); puts(first); memmove(second+5, second, 5); puts(second); return 0; }
como se esperaba, esto va a imprimir:
stackoverflow stackstacklow stackstacklow
Sin embargo, en este ejemplo, los resultados no será el mismo:
#include <stdio.h> #include <string.h> int main (void) { char string [] = "stackoverflow"; char *third, *fourth; third = string; fourth = string; puts(string); memcpy(third+5, third, 7); puts(third); memmove(fourth+5, fourth, 7); puts(fourth); return 0; }
Salida:
stackoverflow stackstackovw stackstackstw
Se debe a que "memcpy()" hace lo siguiente:
1. stackoverflow
2. stacksverflow
3. stacksterflow
4. stackstarflow
5. stackstacflow
6. stackstacklow
7. stackstacksow
8. stackstackstw
buen ejemplo muestra bien la diferencia – bjackfly
¡Pero parece que la salida que mencionó está invertida! – kumar
Cuando ejecuto el mismo programa, obtengo el siguiente resultado: stackoverflow stackstackstw stackstackstw // significa que NO HAY diferencia en la salida entre memcpy y memmove – kumar
Intenté funcionar por encima de código: La razón principal quiero saber la diferencia de memcpy
y memmove
.
#include <stdio.h>
#include <string.h>
int main (void)
{
char string [] = "stackoverflow";
char *third, *fourth;
third = string;
fourth = string;
puts(string);
memcpy(third+5, third, 7);
puts(third);
memmove(fourth+5, fourth, 7);
puts(fourth);
return 0;
}
da debajo de la salida
stackoverflow
stackstackovw
stackstackstw
Ahora he reemplazado con memmove
memcpy
y me dio la misma salida
#include <stdio.h>
#include <string.h>
int main (void)
{
char string [] = "stackoverflow";
char *first, *second;
first = string;
second = string;
puts(string);
memcpy(first+5, first,7);
puts(first);
memcpy(second+5, second, 7);
puts(second);
return 0;
}
Salida:
stackoverflow
stackstackovw
stackstackstw
Eso solo da un único punto de datos en una plataforma. Es muy posible que encuentre (en su plataforma) que 'memcpy (first + 5, first, 7)' se comporta de forma diferente a 'memmove' con los mismos argumentos. –
simplemente fr om el estándar ISO/IEC: 9899 está bien descrito.
7.21.2.1 La función memcpy
[...]
2 La función copia memcpy n caracteres del objeto apuntado por s2 en el objeto apuntado por s1. Si la copia se realiza entre objetos que se superponen, el comportamiento no está definido.
Y
7.21.2.2 La función memmove
[...]
2 La función copia memmove n caracteres del objeto apuntado por s2 en el objeto apuntado por s1. La copia se lleva a cabo como si los n caracteres del objeto apuntados por s2 se copiaran primero en una matriz temporal de n caracteres que no se se superponen los objetos apuntados por s1 y s2, y luego los n caracteres del matriz temporal se copian en el objeto señalado por s1.
Cuál usualmente uso según la pregunta, depende de qué función necesito.
en texto plano memcpy()
no permite s1
y s2
a solaparse, mientras memmove()
hace.
cadena de caracteres [] = "stackoverflow";
char *first, *second;
first = string;
second = string;
puts(string);
o/p - Stackoverflow
memcpy(first+5, first,7);
puts(first);
Aquí 7 caracteres apuntados por segundo es decir, "stackov" pegado en 5 posición resultante
o/p - stackstackovw
memcpy(second+5, second, 7);
puts(second);
aquí la cadena de entrada es "stackstackovw", 7 caracteres apuntados por segundo (i.e "stackst") se copia en una memoria intermedia, entonces pegada en el lugar de 5 resultante
o/p - stackstackstw
0 ----- + 5
stackst pila w
Hay son dos maneras obvias para implementar mempcpy(void *dest, const void *src, size_t n)
(ignorando el valor de retorno):
for (char *p=src, *q=dest; n-->0; ++p, ++q) *q=*p;
char *p=src, *q=dest; while (n-->0) q[n]=p[n];
En la primera implementación, la copia procede de direcciones bajas a altas, y en el segundo, de mayor a menor. Si el rango que se va a copiar se superpone (como ocurre cuando se desplaza un framebuffer, por ejemplo), solo una dirección de operación es correcta y la otra sobrescribirá las ubicaciones de las que posteriormente se leerá.
Una implementación de memmove()
, en su forma más simple, probará dest<src
(de alguna manera dependiente de la plataforma), y ejecutará la dirección apropiada de memcpy()
.
El código de usuario no puede hacer eso, por supuesto, porque incluso después de convertir src
y dst
en algún tipo de puntero concreto, no apuntan (en general) al mismo objeto y, por lo tanto, no se pueden comparar. Pero la biblioteca estándar puede tener suficiente conocimiento de plataforma para realizar dicha comparación sin causar un Comportamiento no definido.
Tenga en cuenta que en la vida real, las implementaciones tienden a ser significativamente más complejo, para obtener el máximo rendimiento de las transferencias más grandes (cuando lo permita la alineación) y/o una buena utilización de caché de datos. El código anterior es solo para hacer el punto lo más simple posible.
memmove puede ocuparse de la superposición de regiones de origen y destino, mientras que memcpy no. Entre los dos, memcpy es mucho más eficiente. Entonces, es mejor usar memcpy si puedes.
Referencia: https://www.youtube.com/watch?v=Yr1YnOVG-4g Dr. Jerry Caín, (Stanford Introducción Sistemas de Conferencia - 7) Hora: 36:00
[Esta respuesta] (http://stackoverflow.com/a/28624068/2410359) dice "posiblemente un smidge más rápido" y proporciona datos cuantitativos que indican solo una pequeña diferencia. Esta respuesta afirma que uno es "mucho más eficiente". ¿Cuánto más eficiente ha encontrado el más rápido para ser? Por cierto: supongo que te refieres a 'memcpy()' y no a 'memcopy()'. – chux
El comentario está basado en la conferencia del Dr. Jerry Cain. Le pediría que escuchara su conferencia a las 36:00, solo 2-3 minutos serán suficientes. Y gracias por la captura. :RE – Ehsan
- 1. Cuál es la diferencia entre memset y memcpy en C
- 2. optimizaciones std :: copy/memcpy/memmove
- 3. Diferencia entre strncpy y memcpy?
- 4. ¿Cuál es la diferencia entre " " y ""?
- 5. ¿cuál es la diferencia entre:.! y: r !?
- 6. ¿Cuál es la diferencia entre ".equals" y "=="?
- 7. Cuál es la diferencia entre = y: =
- 8. ¿Cuál es la diferencia entre [indefinido] y [,]?
- 9. ¿Cuál es la diferencia entre .ToString (+) y ""
- 10. Cuál es la diferencia entre $ (...) y `...`
- 11. ¿Cuál es la diferencia entre `##` y `hashCode`?
- 12. ¿Cuál es la diferencia entre + = y = +?
- 13. ¿Cuál es la diferencia entre dict() y {}?
- 14. Cuál es la diferencia entre $ y jQuery
- 15. ¿Cuál es la diferencia entre "$^N" y "$ +"?
- 16. ¿Cuál es la diferencia entre {0} y ""?
- 17. OpenGL (ES) - ¿Cuál es la diferencia entre frustum y orto?
- 18. ¿Cuál es la diferencia entre la abstracción y la encapsulación?
- 19. Cuál es la diferencia entre la función() {}() y la función() {}()
- 20. ¿Cuál es la diferencia entre @ y $ y% en MSBuild?
- 21. ¿Cuál es la diferencia entre la vinculación estática y dinámica?
- 22. ¿Cuál es la diferencia entre la carpeta vim72 y vimfiles?
- 23. ¿cuál es la diferencia entre el complemento y la biblioteca?
- 24. ¿Cuál es la diferencia entre CookieContainer y la colección Response.Cookies?
- 25. ¿Cuál es la diferencia entre la tubería y el zócalo?
- 26. ¿Cuál es la diferencia entre la relación Composición y Asociación?
- 27. ¿Cuál es la diferencia entre la sección .got y .got.plt?
- 28. ¿cuál es la diferencia entre el material y la textura?
- 29. ¿Cuál es la diferencia entre WPF y la aplicación Silverlight?
- 30. ¿Cuál es la diferencia entre el casting y la conversión?
revertido debido Worrier reintrodujo mala gramática. Él puede editar las etiquetas nuevamente si lo desea. – Welbog
Me parece que ustedes dos corrieron en una edición y Worrier no cambió el cuerpo del original :) – bdonlan
Tenga en cuenta los problemas que pueden surgir: https://lwn.net/Articles/414467/ –