206 votes

memcpy () vs memmove ()

Je suis en train d'essayer de comprendre la différence entre memcpy() et memmove(), et j'ai lu le texte que memcpy ne prend pas soin de le chevauchement de la source et de la destination wheras memmove() .

Cependant, lorsque j'exécute ces deux fonctions sur le chevauchement des blocs de mémoire, ils ont tous les deux donnent le même résultat. Par exemple, prenez la suite MSDNexample sur l' memmove() page d'aide:-

Est-il un meilleur exemple pour comprendre les inconvénients de memcpy et comment memmove elle n'en résout?

// crt_memcpy.c
// Illustrate overlapping copy: memmove always handles it correctly; memcpy may handle
// it correctly.

#include <memory.h>
#include <string.h>
#include <stdio.h>

char str1[7] = "aabbcc";

int main( void )
{
    printf( "The string: %s\n", str1 );
    memcpy( str1 + 2, str1, 4 );
    printf( "New string: %s\n", str1 );

    strcpy_s( str1, sizeof(str1), "aabbcc" );   // reset string

    printf( "The string: %s\n", str1 );
    memmove( str1 + 2, str1, 4 );
    printf( "New string: %s\n", str1 );
}

Sortie:

The string: aabbcc
New string: aaaabb
The string: aabbcc
New string: aaaabb

157voto

developmentalinsanity Points 3729

Je ne suis pas complètement surpris que votre exemple ne présente pas de comportement étrange. Essayez de copier str1 de str1+2 au lieu de cela et voir ce qui se passe ensuite. (Ne peut pas réellement faire une différence, dépend du compilateur/bibliothèques).

En général, memcpy est mis en œuvre de façon simple (mais rapide). Grosso modo, c'est juste des boucles sur les données (dans l'ordre), la copie d'un endroit à l'autre. Cela peut entraîner la source est écrasé alors qu'il est en cours de lecture.

Memmove n'a plus de travail pour s'assurer qu'il gère le chevauchement correctement.

EDIT:

(malheureusement, je ne peux pas trouver un travail décent exemples, mais de le faire). Le contraste le memcpy et memmove implémentations montré ici. memcpy juste les boucles, tout en memmove effectue un test pour déterminer le sens dans lequel la boucle pour éviter de corrompre les données. Ces implémentations sont plutôt simples. Les plus hautes performances de mise en œuvre est plus complexe (impliquant la copie mot-blocs de taille à un moment plutôt qu'en octets).

130voto

rxantos Points 481

La mémoire en mémoire ne peut pas se chevaucher, alors que la mémoire en mémoire peut se chevaucher.

 char a[16];
char b[16];

memcpy(a,b,16);           // valid
memmove(a,b,16);          // Also valid, but slower than memcpy.
memcpy(&a[0], &a[1],10);  // Not valid since it overlaps.
memmove(&a[0], &a[1],10); // valid. 
 

Certaines implémentations de memcpy peuvent encore fonctionner en cas de chevauchement. Mais vous ne pouvez pas compter de ce comportement. Même si memmove doit permettre le chevauchement.

39voto

Billy ONeal Points 50631

Ce n'est pas parce que memcpy ne doit pas traiter avec des régions qui se chevauchent que cela ne signifie pas qu'il ne les traite pas correctement. L'appel avec des régions qui se chevauchent produit un comportement indéfini. Un comportement indéfini peut fonctionner entièrement comme vous le souhaitez sur une plate-forme. cela ne signifie pas que c'est correct ou valide.

20voto

Neilvert Noval Points 796

Memcpy et memove font les mêmes choses.

Mais pour observer une différence:

 #include <memory.h>
#include <string.h>
#include <stdio.h>

char str1[17] = "abcdef";

int main()
{

   printf( "The string: %s\n", str1 );
   memcpy( (str1+6), str1, 10 );
   printf( "New string: %s\n", str1 );

   strcpy_s( str1, sizeof(str1), "aabbcc" );   // reset string

   printf( "The string: %s\n", str1 );
   memmove( (str1+6), str1, 10 );
   printf( "New string: %s\n", str1 );

}
 

donne:

 The string: abcdef
New string: abcdefabcdefabcd
The string: abcdef
New string: abcdefabcdef
 

14voto

huubby Points 90

Votre démonstration ne pas exposer memcpy inconvénients en raison de la "mauvaise" compilateur, il ne vous une faveur dans la version de Débogage. Une version, cependant, vous donne le même résultat, mais en raison de l'optimisation.

    memcpy(str1 + 2, str1, 4);
00241013  mov         eax,dword ptr [str1 (243018h)]  // load 4 bytes from source string
    printf("New string: %s\n", str1);
00241018  push        offset str1 (243018h) 
0024101D  push        offset string "New string: %s\n" (242104h) 
00241022  mov         dword ptr [str1+2 (24301Ah)],eax  // put 4 bytes to destination
00241027  call        esi  

Le registre %eax joue ici comme un stockage temporaire, qui "élégamment" correctifs de problème de chevauchement.

L'inconvénient émerge lors de la copie de 6 octets, et bien, au moins en partie.

char str1[9] = "aabbccdd";

int main( void )
{
    printf("The string: %s\n", str1);
    memcpy(str1 + 2, str1, 6);
    printf("New string: %s\n", str1);

    strcpy_s(str1, sizeof(str1), "aabbccdd");   // reset string

    printf("The string: %s\n", str1);
    memmove(str1 + 2, str1, 6);
    printf("New string: %s\n", str1);
}

Sortie:

The string: aabbccdd
New string: aaaabbbb
The string: aabbccdd
New string: aaaabbcc

Un peu bizarre, il est causé par l'optimisation, trop.

    memcpy(str1 + 2, str1, 6);
00341013  mov         eax,dword ptr [str1 (343018h)] 
00341018  mov         dword ptr [str1+2 (34301Ah)],eax // put 4 bytes to destination, earlier than the above example
0034101D  mov         cx,word ptr [str1+4 (34301Ch)]  // HA, new register! Holding a word, which is exactly the left 2 bytes (after 4 bytes loaded to %eax)
    printf("New string: %s\n", str1);
00341024  push        offset str1 (343018h) 
00341029  push        offset string "New string: %s\n" (342104h) 
0034102E  mov         word ptr [str1+6 (34301Eh)],cx  // Again, pulling the stored word back from the new register
00341035  call        esi  

C'est pourquoi j'ai toujours choisissez memmove lors de la tentative de copie 2 se chevauchent les blocs de mémoire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X