Ich versuche den Unterschied zwischen zu verstehen memcpy() und memmove()und ich habe den Text gelesen, dass memcpy() kümmert sich nicht um die Überlappung von Quelle und Ziel, während memmove() tut.
Wenn ich diese beiden Funktionen jedoch auf überlappenden Speicherblöcken ausführe, liefern sie beide das gleiche Ergebnis. Nehmen Sie zum Beispiel das folgende MSDN-Beispiel auf der memmove() Hilfeseite:-
Gibt es ein besseres Beispiel, um die Nachteile zu verstehen? memcpy und wie memmove löst es?
// 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 );
}
Ausgabe:
The string: aabbcc
New string: aaaabb
The string: aabbcc
New string: aaaabb
Die Microsoft CRT hat seit geraumer Zeit ein sicheres memcpy().
– Hans Passant
11. Dezember 2010 um 9:01 Uhr
Ich glaube nicht, dass “sicher” das richtige Wort dafür ist. Ein Tresor memcpy möchten assert dass sich die Regionen nicht überlappen, anstatt absichtlich Fehler in Ihrem Code zu verdecken.
– R.. GitHub HÖR AUF, EIS ZU HELFEN
11. Dezember 2010 um 12:53 Uhr
Hängt davon ab, ob Sie “sicher für den Entwickler” oder “sicher für den Endbenutzer” meinen. Ich würde argumentieren, dass es für den Endbenutzer die sicherere Wahl ist, das Gesagte zu tun, auch wenn es nicht standardkonform ist.
Ein gutes Beispiel mit Bildern zum Thema „Was alles schief gehen kann memcpy(...) finden Sie hier: memcpy gegen memmove.
– Deralbert
4. Oktober 2020 um 14:18 Uhr
Entwicklungswahnsinn
Ich bin nicht ganz überrascht, dass Ihr Beispiel kein seltsames Verhalten zeigt. Versuchen Sie es mit Kopieren str1 zu str1+2 stattdessen und sehen, was dann passiert. (Möglicherweise keinen Unterschied machen, abhängig von Compiler/Bibliotheken.)
Im Allgemeinen ist memcpy auf einfache (aber schnelle) Weise implementiert. Vereinfacht gesagt werden die Daten einfach (in der Reihenfolge) durchlaufen und von einem Ort zum anderen kopiert. Dies kann dazu führen, dass die Quelle beim Lesen überschrieben wird.
Memmove leistet mehr Arbeit, um sicherzustellen, dass die Überlappung korrekt gehandhabt wird.
BEARBEITEN:
(Leider kann ich keine anständigen Beispiele finden, aber diese reichen aus). Kontrastieren Sie die memcpy und memmove hier gezeigten Implementierungen. memcpy macht einfach eine Schleife, während memmove einen Test durchführt, um zu bestimmen, in welche Richtung eine Schleife eingefügt werden soll, um eine Beschädigung der Daten zu vermeiden. Diese Implementierungen sind ziemlich einfach. Die meisten Hochleistungsimplementierungen sind komplizierter (sie beinhalten das gleichzeitige Kopieren von Blöcken in Wortgröße anstelle von Bytes).
Das klingt gut. Anscheinend implementiert Visual Studio ein “sicheres” Memcpy (zusammen mit gcc 4.1.1 habe ich es auch auf RHEL 5 getestet). Das Schreiben der Versionen dieser Funktionen von clc-wiki.net ergibt ein klares Bild. Vielen Dank.
– Benutzer534785
11. Dezember 2010 um 9:24 Uhr
memcpy kümmert sich nicht um das Überlappungsproblem, aber memmove tut es. Warum dann memcpy nicht aus der Bibliothek entfernen?
Die Erinnerung an memcpykann nicht sich überschneiden oder Sie riskieren ein undefiniertes Verhalten, während die Erinnerung drin ist memmove überlappen können.
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.
Einige Implementierungen von memcpy funktionieren möglicherweise immer noch für überlappende Eingaben, aber Sie können dieses Verhalten nicht zählen. Während memmove Überlappungen zulassen muss.
es hat mir wirklich geholfen, danke! +1 für deine Info
– Muthu Ganapathy Nathan
28. August 2011 um 12:41 Uhr
Nur weil memcpy nicht mit überlappenden Regionen umgehen muss, bedeutet nicht, dass es sie nicht korrekt behandelt. Der Aufruf mit überlappenden Regionen erzeugt ein undefiniertes Verhalten. Undefiniertes Verhalten kann auf einer Plattform vollständig so funktionieren, wie Sie es erwarten; das bedeutet nicht, dass es richtig oder gültig ist.
Insbesondere je nach Plattform ist das möglich memcpy wird genauso implementiert wie memmove. Das heißt, wer auch immer den Compiler geschrieben hat, hat sich nicht die Mühe gemacht, ein Unique zu schreiben memcpy Funktion.
– Kamera
11. Dezember 2010 um 8:46 Uhr
Neilvert Noval
Sowohl memcpy als auch memove machen ähnliche Dinge.
The string: abcdef
New string: abcdefabcdefabcd
The string: abcdef
New string: abcdefabcdef
Ihre Demo hat Memcpy-Nachteile wegen des “schlechten” Compilers nicht aufgedeckt, sie tut Ihnen in der Debug-Version einen Gefallen. Eine Release-Version gibt Ihnen jedoch die gleiche Ausgabe, jedoch aufgrund der Optimierung.
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
Das Register %eax spielt hier als temporärer Speicher, der das Überlappungsproblem “elegant” behebt.
Der Nachteil tritt auf, wenn 6 Bytes kopiert werden, zumindest ein Teil davon.
The string: aabbccdd
New string: aaaabbbb
The string: aabbccdd
New string: aaaabbcc
Sieht komisch aus, liegt auch an der Optimierung.
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
Deshalb wähle ich immer memmove beim Versuch, 2 überlappende Speicherblöcke zu kopieren.
Pimgd
Der Unterschied zwischen memcpy und memmove ist das
in memmove, wird der Quellspeicher der angegebenen Größe in den Puffer kopiert und dann zum Ziel verschoben. Wenn sich der Speicher also überlappt, gibt es keine Nebenwirkungen.
im Falle von memcpy(), wird kein zusätzlicher Puffer für den Quellspeicher verwendet. Das Kopieren erfolgt direkt im Speicher, so dass wir bei einer Speicherüberlappung unerwartete Ergebnisse erhalten.
Diese können durch den folgenden Code beobachtet werden:
//include string.h, stdio.h, stdlib.h
int main(){
char a[]="hare rama hare rama";
char b[]="hare rama hare rama";
memmove(a+5,a,20);
puts(a);
memcpy(b+5,b,20);
puts(b);
}
Ausgabe ist:
hare hare rama hare rama
hare hare hare hare hare hare rama hare rama
2 Die Funktion memcpy kopiert n Zeichen aus dem Objekt, auf das s2 zeigt, in das Objekt, auf das s1 zeigt. Wenn zwischen sich überlappenden Objekten kopiert wird, ist das Verhalten undefiniert.
7.24.2.2 „Die memmove-Funktion“:
2 Die Funktion memmove kopiert n Zeichen aus dem Objekt, auf das s2 zeigt, in das Objekt, auf das s1 zeigt. Das Kopieren erfolgt so, als ob die n Zeichen aus dem Objekt, auf das s2 zeigt, zuerst in ein temporäres Array aus n Zeichen kopiert werden, das die Objekte, auf die s1 und s2 zeigen, nicht überlappt, und dann werden die n Zeichen aus dem temporären Array hineinkopiert das Objekt, auf das s1 zeigt
Daher überlappen sich keine memcpy führt zu undefiniertem Verhalten, und alles kann passieren: schlecht, nichts oder sogar gut. Gut ist selten 🙂
memmove sagt aber eindeutig, dass alles so passiert, als ob ein Zwischenpuffer verwendet wird, also sind eindeutige Überschneidungen OK.
C++ std::copy ist jedoch nachsichtiger und erlaubt Überlappungen: Behandelt std::copy überlappende Bereiche?
memmove Verwenden Sie ein zusätzliches temporäres Array von n, also wird zusätzlicher Speicher verwendet? Aber wie kann es, wenn wir ihm keinen Zugriff auf irgendeinen Speicher gegeben haben. (Es verwendet 2x den Speicher).
– Clementjohn
27. März 2019 um 4:42 Uhr
@clmno ordnet es wie jede andere Funktion, die ich erwarten würde, auf Stack oder Malloc zu 🙂
– Ciro Santilli OurBigBook.com
27. März 2019 um 18:30 Uhr
Ich hatte hier eine Frage gestellt, bekam auch eine gute Antwort. Vielen Dank. Ich habe Ihre Hackernews gesehen Post das ging viral (das x86) 🙂
Die Microsoft CRT hat seit geraumer Zeit ein sicheres memcpy().
– Hans Passant
11. Dezember 2010 um 9:01 Uhr
Ich glaube nicht, dass “sicher” das richtige Wort dafür ist. Ein Tresor
memcpy
möchtenassert
dass sich die Regionen nicht überlappen, anstatt absichtlich Fehler in Ihrem Code zu verdecken.– R.. GitHub HÖR AUF, EIS ZU HELFEN
11. Dezember 2010 um 12:53 Uhr
Hängt davon ab, ob Sie “sicher für den Entwickler” oder “sicher für den Endbenutzer” meinen. Ich würde argumentieren, dass es für den Endbenutzer die sicherere Wahl ist, das Gesagte zu tun, auch wenn es nicht standardkonform ist.
– Kusma
26. Januar 2012 um 12:33 Uhr
Microsofts „sicheres“ memcpy() ist ein Fallback auf memmove() twitter.com/MalwareMinigun/status/737801492808142848
– vobjekt
1. Juni 2016 um 1:33 Uhr
Ein gutes Beispiel mit Bildern zum Thema „Was alles schief gehen kann
memcpy(...)
finden Sie hier: memcpy gegen memmove.– Deralbert
4. Oktober 2020 um 14:18 Uhr