2010-08-26 19 views
5

Kann mir jemand helfen zu verstehen, wie Memmove in C implementiert ist. Ich habe nur eine spezielle Bedingung richtig?memmove Implementierung in C

if((src<dst)&&((src+sz) > dst)) 

copy from the back 

Kommt es auch auf die Art und Weise an, wie der Stack wächst?

+0

Wenn 'src',' dst' und 'sz' alle positive Werte sind, ist die Bedingung unerfüllbar. Wenn 'src> dst' ist, wird das Hinzufügen von positivem' sz' es nicht weniger machen. – Edmund

+0

@Edmund Ich korrigierte – brett

Antwort

28

Mathematisch müssen Sie sich keine Gedanken darüber machen, ob sie sich überhaupt überschneiden. Wenn src kleiner als dst ist, kopieren Sie einfach vom Ende. Wenn src größer als dst ist, kopieren Sie einfach von Anfang an.

Wenn src und dst gleich sind, einfach gleich wieder verlassen.

Das ist, weil Ihre Fälle sind eines von:

1) <-----s----->    start at end of s 
       <-----d-----> 

2) <-----s----->    start at end of s 
      <-----d-----> 

3) <-----s----->    no action 
    <-----d-----> 

4)   <-----s----->  start at beginning of s 
    <-----d-----> 

5)    <-----s-----> start at beginning of s 
    <-----d-----> 

Auch wenn es keine Überlappung, die wird immer noch gut funktionieren und Ihre Bedingungen vereinfachen.

Wenn Sie einen effizienteren Weg haben, vorwärts als rückwärts zu kopieren, dann sollten Sie nach Überlappung suchen, um sicherzustellen, dass Sie die effizienteste Methode verwenden, wenn möglich. Mit anderen Worten, ändern Sie Option 1 oben, um von Anfang an zu kopieren.

+1

Beachten Sie, dass es eine weitere versteckte Annahme hier, dass Sie nur ein Byte nach dem anderen kopieren. – caf

+2

Nun, ob Sie ein Byte zu einem Zeitpunkt oder ein Vierwort oder einen massiven SSE9 1024-Bit-Hyperwort-Wert kopieren, bleibt die Theorie die gleiche.Sie müssen sicherstellen, dass Sie _into_ keinen Überlappungsbereich kopieren, den Sie noch nicht kopiert haben. Alle N-ist-breiter-als-Zeichen-Optionen eingeführt ist eine etwas komplexere Erkennung der Überlappung (und endgültige Übertragung) in dem Fall, wenn es kein direktes Vielfaches des Wertes von N. – paxdiablo

+0

@caf: Wenn 'src' und 'dest' haben die gleiche Ausrichtung in Bezug auf einen größeren Typ, den Sie kopieren könnten, aber Sie müssen sich niemals Gedanken darüber machen, ob Sie einen Bereich kopieren, den Sie noch nicht kopiert haben, da sich die Positionen immer mindestens um diese Größe unterscheiden. Wenn sie nicht die gleiche Ausrichtung haben, müssen Sie sowieso als Byte kopieren ... es sei denn, Sie möchten einige böse x86 unaligned io verwenden ... –

1

Hängt vom Compiler ab. Gute Compiler verwenden gute Optimierungen abhängig vom Zielprozessor-Befehlssatz und der Busbreite.

+0

Ich glaube, das sollte in einen Kommentar anstelle der separaten Antwort gehen – YeenFei

5

memmove kann in einen Memcpy umgewandelt werden, wenn sich die beiden Speicherbereiche nicht überschneiden. Offensichtlich ist memcpy auf den meisten Systemen extrem optimiert (eine von denen, die ich verwende, macht fast jeden Trick aus dem Buch von entrollten Schleifen zu SSE-Operationen, wo für maximalen Durchsatz unterstützt wird).

Wenn sich die beiden Speicherbereiche überlappen, wird die zu kopierende Region praktisch in einen temporären Puffer verschoben und der temporäre Puffer wird (höchstwahrscheinlich mit memcpy) wieder über den ursprünglichen Puffer kopiert. Sie können nicht von Anfang an arbeiten oder von hinten mit einer überlappenden Region arbeiten, da Sie dadurch immer mindestens einige Daten verlieren, die dabei beschädigt werden.

Das ist gesagt, es ist eine lange Zeit her, seit ich den libc-Code angeschaut habe, also könnte es eine Optimierung für memmove und überlappende Regionen geben, an die ich noch nicht gedacht habe.

memmove hängt nicht davon ab, wie der Stack überhaupt wächst - er kopiert lediglich einen Speicherbereich an einen anderen Speicherort - genau wie memcpy, außer dass er überlappende Bereiche behandelt und memcpy nicht.

EDIT: Eigentlich darüber etwas mehr denken ... Arbeiten von der Rückseite kann funktionieren, wenn Sie von der richtigen "Quelle" gehen (sozusagen), abhängig von der Bewegung selbst (zB ist Quelle < dest oder nicht?). Sie können die Implementierung von newlib here lesen, und tt ist auch ziemlich gut kommentiert.

+0

Ich würde gerne sehen, Sie kopieren in einen temporären Puffer, wenn 'n' ist' SIZE_MAX >> 1' ... –