2013-07-06 10 views
13

Wie funktioniert die Standard-C-Funktion "memcpy"? Es muss ein (großes) Stück RAM in einen anderen Bereich im RAM kopieren. Da ich weiß, dass man nicht direkt von RAM zu RAM in Assembly wechseln kann (mit der mov-Anweisung), nehme ich an, dass es beim Kopieren ein CPU-Register als Zwischenspeicher verwendet.Wie funktioniert die interne Implementierung von memcpy?

Aber wie kopiert es? Nach Blöcken (wie würde es nach Blöcken kopieren?), Nach einzelnen Bytes (char) oder dem größten Datentyp, den sie haben (lange long double kopieren - das sind 12 Bytes auf meinem System).

EDIT: Ok anscheinend können Sie Daten aus dem RAM bewegen direkt auf RAM, ich bin kein Montag Experte und alles, was ich gelernt habe, über Assembly aus diesem Dokument (X86 assembly guide), die über den MOV-Befehl in dem Abschnitt erwähnt, dass Sie können nicht von RAM zu RAM wechseln. Anscheinend stimmt das nicht.

+0

Dies ist plattformspezifisch. Bitte geben Sie eine Plattform an. –

+0

Ich benutze Linux, Mac & Windows (32-Bit, 64-Bit und 32-Bit), aber ich stellte diese Frage bei der Verwendung von Linux. – hddh

Antwort

14

Hängt davon ab. Im Allgemeinen können Sie in einem einzigen Zyklus nichts Größeres als das größte verwendbare Register physisch kopieren, aber das ist heute nicht so, wie Maschinen heutzutage funktionieren. In der Praxis interessiert es Sie weniger, was die CPU macht und mehr über die Eigenschaften von DRAM. Die Speicherhierarchie der Maschine spielt eine entscheidende Rolle bei der Durchführung dieser Kopie auf die schnellstmögliche Weise (z. B. laden Sie ganze Cache-Zeilen? Welche Größe hat eine DRAM-Zeile in Bezug auf den Kopiervorgang?). Eine Implementierung könnte stattdessen eine Art von Vektoranweisungen verwenden, um memcpy zu implementieren. Ohne Bezugnahme auf eine bestimmte Implementierung ist dies effektiv eine Byte-für-Byte-Kopie mit einem Ein-Platz-Puffer.

Here's a fun article beschreibt das Abenteuer einer Person in die Optimierung memcpy. Der wichtigste Punkt ist, dass es immer auf eine bestimmte Architektur und Umgebung ausgerichtet ist, basierend auf den Anweisungen, die Sie kostengünstig ausführen können.

4

Eine triviale Implementierung von memcpy ist:

while (n--) *s2++ = *s1++; 

Aber glibc verwendet in der Regel einige clevere Implementierungen in Code-Anordnung. memcpy Anrufe sind in der Regel inline.

Auf x86, die Code überprüft, ob der Größenparameter ein Literal Vielfaches von 2 oder ein Vielfaches von 4 (unter Verwendung von gcc builtins Funktionen) ist und verwendet eine Schleife mit movl Befehl (kopieren 4 bytes) andernfalls ruft sie der allgemeine Fall.

Der allgemeine Fall verwendet die schnelle Blockkopie Assembly mit rep und movsl Anweisungen.

6

Die Implementierung von memcpy ist sehr spezifisch für das System, in dem es implementiert ist. Implementierungen werden oft hardwareunterstützt.

Speicher-zu-Speicher-mov Anweisungen sind nicht so ungewöhnlich - sie gibt es schon seit mindestens PDP-11 mal, wenn Sie so etwas schreiben könnte:

MOV FROM, R2 
    MOV TO, R3 
    MOV R2, R4 
    ADD LEN, R4 
CP: MOV (R2+), (R3+) ; "(Rx+)" means "*Rx++" in C 
    CMP R2, R4 
    BNE CP 

Die kommentierte Linie C entspricht ungefähr ist

*to++ = *from++; 

Moderne CPUs Anweisungen haben, die memcpy direkt implementieren: Sie spezielles Register mit den Quell- und Zieladressen zu laden, einen Speicherkopierbefehl aufrufe und läßt CPU den Rest.

+0

"sie sind seit mindestens PDP-11 mal da" - viel länger. –

+0

@JimBalter Das überrascht mich überhaupt nicht :) – dasblinkenlight

Verwandte Themen