Frage

Was ist der Unterschied zwischen memmove und memcpy? Welches verwenden Sie in der Regel und wie?

War es hilfreich?

Lösung

Mit memcpy kann das Ziel nicht die Quelle überlappt überhaupt. Mit memmove kann es. Das bedeutet, dass memmove sehr sein könnte etwas langsamer als memcpy, da es nicht die gleichen Annahmen getroffen werden kann.

Zum Beispiel memcpy könnte immer kopieren Adressen von niedrig bis hoch. Wenn das Ziel nach der Quelle überlappt, bedeutet dies, einige Adressen überschrieben werden, bevor kopiert. memmove würden diese, und kopieren Sie in der anderen Richtung erkennt - von hoch zu niedrig - in diesem Fall. Allerdings überprüft diese und auf einem anderen (möglicherweise weniger effizient) Algorithmus Schalt braucht Zeit.

Andere Tipps

memmove können überlappende Speicher umgehen, memcpy kann es nicht.

Betrachten

char[] str = "foo-bar";
memcpy(&str[3],&str[4],4); //might blow up

Offensichtlich ist die Quelle und das Ziel jetzt überlappen, wir überschreiben "-Bar" mit "bar". Es ist nicht definiertes Verhalten mit memcpy, wenn die Quelle und Ziel-Überlappung so in diesem Fall Fällen brauchen wir memmove.

memmove(&str[3],&str[4],4); //fine

Von der Memcpy man-Seite.

  

Die memcpy () Funktion kopiert n Bytes   aus dem Speicherbereich src zum Speicherbereich   dest. Die Speicherbereiche sollten nicht   Überlappung. Verwenden memmove (3), wenn die Speicher   Bereiche überlappen sich.

Der Hauptunterschied zwischen memmove() und memcpy() ist, dass in memmove() a Puffer - Zwischenspeicher - verwendet wird, so dass es keine Gefahr von Überschneidungen. Auf der anderen Seite, memcpy() direkt kopiert die Daten von der Stelle, die von der Ziel , auf die der source auf den Ort gerichtet ist. ( http://www.cplusplus.com/reference/cstring/memcpy/ )

Beachten Sie die folgenden Beispiele:

  1. #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;
    }
    

    Wie Sie erwarten, wird dies ausdrucken:

    stackoverflow
    stackstacklow
    stackstacklow
    
  2. Aber in diesem Beispiel werden die Ergebnisse nicht gleich sein:

    #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;
    }
    

    Ausgabe:

    stackoverflow
    stackstackovw
    stackstackstw
    

Es ist, weil "memcpy ()" führt Folgendes aus:

1.  stackoverflow
2.  stacksverflow
3.  stacksterflow
4.  stackstarflow
5.  stackstacflow
6.  stackstacklow
7.  stackstacksow
8.  stackstackstw

Eine Griff überlappende Ziele der andere nicht.

einfach von der ISO / IEC. 9899 Standard es gut beschrieben wird,

  

7.21.2.1 Die Memcpy Funktion

     

[...]

     

2 Die Memcpy Funktion kopiert n Zeichen aus dem Objekt, auf dem durch s2 in die   Objekt, auf das durch s1. Wenn das Kopieren zwischen Objekten erfolgt, die sich überlappen, ist das Verhalten nicht definiert.

Und

  

7.21.2.2 Die memmove Funktion

     

[...]

     

2 Die memmove Funktion kopiert n Zeichen aus dem Objekt in die von s2 hingewiesen   Objekt, auf das durch s1. Das Kopieren erfolgt als ob die n Zeichen aus dem Objekt   s2, auf den zunächst in eine temporäre Matrix von n Zeichen kopiert, die nicht der Fall ist   überlappen wiesen die Objekte von s1 und s2, und dann die n Zeichen aus der   temporäres Array kopiert werden in das Objekt von s1 hingewiesen.

Was man in der Regel ich auf die Frage Acording verwenden, hängt davon ab, welche functionallity ich brauche.

Im Klartext memcpy() nicht erlaubt s1 und s2 zu überlappen, während memmove() der Fall ist.

Angenommen, Sie würden beide implementieren, die Umsetzung so aussehen könnte:

void memmove ( void * dst, const void * src, size_t count ) {
    if ((uintptr_t)src < (uintptr_t)dst) {
        // Copy from back to front

    } else if ((uintptr_t)dst < (uintptr_t)src) {
        // Copy from front to back
    }
}

void mempy ( void * dst, const void * src, size_t count ) {
    if ((uintptr_t)src != (uintptr_t)dst) {
        // Copy in any way you want
    }
}

Und das sollte ziemlich gut den Unterschied erklären. memmove immer Kopien so, dass es immer noch sicher ist, wenn src und dst Überlappung, während memcpy gerade interessiert sich nicht wie die Dokumentation sagt, wenn memcpy verwenden, die zwei Speicherbereiche muss nicht überlappen.

z. wenn memcpy Kopien „von vorne nach hinten“ und die Speicherblöcke sind als diese ausgerichtet

[---- src ----]
            [---- dst ---]

das erste Byte src Kopieren zerstört dst bereits den Inhalt des letzten Bytes src bevor diese kopiert wurde. Nur „hinten nach vorne“ zu kopieren, um korrekten Ergebnissen führen wird.

Jetzt tauschen src und dst:

[---- dst ----]
            [---- src ---]

In diesem Fall ist es nur sicher zu kopieren, wie das Kopieren "Front to Back" "hinten nach vorne" würde src in der Nähe seiner Vorderseite zerstört bereits, wenn das erste Byte zu kopieren.

Sie haben vielleicht bemerkt, dass die memmove Implementierung oben noch nicht testen, ob sie tatsächlich überlappen, sie ihre relativen Positionen nur überprüft, aber das allein wird die Kopie sicher machen. Als memcpy in der Regel auf den schnellsten Weg nutzt den Hauptspeicher auf jedem System zu kopieren, wird memmove in der Regel eher umgesetzt als:

void memmove ( void * dst, const void * src, size_t count ) {
    if ((uintptr_t)src < (uintptr_t)dst
        && (uintptr_t)src + count > (uintptr_t)dst
    ) {
        // Copy from back to front

    } else if ((uintptr_t)dst < (uintptr_t)src
        && (uintptr_t)dst + count > (uintptr_t)src
    ) {
        // Copy from front to back

    } else {
        // They don't overlap for sure
        memcpy(dst, src, count);
    }
}

Manchmal, wenn memcpy immer Kopien „von vorne nach hinten“ oder „hinten nach vorne“, memmove auch memcpy in eines der überlappenden Fällen verwenden können, aber memcpy können kopieren, auch in einer anderen Art und Weise, je nachdem wie die Daten ausgerichtet ist und / oder wie viele Daten kopiert werden, so dass selbst wenn Sie getestet, wie memcpy Kopien auf Ihrem System, können Sie nicht auf diesem Testergebnis verlassen immer korrekt zu sein.

Was bedeutet das für Sie bei der Entscheidung, die man anrufen?

  1. Wenn Sie nicht sicher wissen, dass src und dst sich nicht überlappen, ruft memmove wie es immer Ergebnisse führen zu korrigieren und ist in der Regel so schnell wie die für die Kopie Fall möglich ist, die Sie benötigen.

  2. Wenn Sie sicher wissen, dass src und dst nicht überlappen, Call memcpy als es keine Rolle, wird, welche Sie für das Ergebnis nennen, die beide in diesem Fall korrekt funktionieren, aber memmove nie schneller als memcpy und noch langsamer kann es sein, wenn man Pech hat, kann man nur so nennen memcpy gewinnen.

Es gibt zwei offensichtliche Wege mempcpy(void *dest, const void *src, size_t n) (ohne Berücksichtigung der Rückgabewert) zu implementieren:

  1. for (char *p=src, *q=dest;  n-->0;  ++p, ++q)
        *q=*p;
    
  2. char *p=src, *q=dest;
    while (n-->0)
        q[n]=p[n];
    

In der ersten Implementierung, die Kopie Erlös von niedrigen zu hohen Adressen und in der zweiten, von hoch zu niedrig. Wenn der Bereich Überschneidungen kopiert wird (wie es der Fall ist, wenn ein Framebuffer, zum Beispiel Scrollen), dann wird nur eine Arbeitsrichtung richtig ist, und die andere überschreiben Orte, die anschließend aus gelesen werden.

A memmove() Implementierung Im einfachsten wird, testen dest<src (in einiger plattformabhängigen Art und Weise), und die entsprechende Richtung des memcpy() auszuführen.

Code Der Benutzer kann das natürlich nicht tun, denn auch nach src und dst bis zu einem gewissen konkreten Zeigerart Gießen, sie nicht (im Allgemeinen) in das gleiche Objekt zeigen und so nicht miteinander verglichen werden können. Aber die Standard-Bibliothek kann genug Plattform Wissen haben einen solchen Vergleich durchzuführen, ohne nicht definiertes Verhalten zu verursachen.


Beachten Sie, dass im wirklichen Leben, Implementierungen sind in der Regel wesentlich komplexer sein, um die maximale Leistung aus größeren Transfers zu gewinnen (wenn die Ausrichtung zulässt) und / oder gute Daten-Cache-Nutzung. Der obige Code ist nur um den Punkt zu machen so einfach wie möglich.

memmove kann mit überlappenden Quell- und Zielregionen beschäftigen, während Memcpy nicht. Unter den beiden ist Memcpy wesentlich effizienter. Also, besser nutzen es MEMCPY wenn Sie können.

Referenz: https://www.youtube.com/watch?v=Yr1YnOVG -4G Dr. Jerry Cain (Stanford Intro Systeme Vortrag - 7) Zeit: 36:00

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top