Können memcpy oder memmove einen anderen Zeiger als dest zurückgeben?

Lesezeit: 5 Minuten

Benutzeravatar von Martin Ueding
Martin Üding

Die Funktion memmove ist so definiert:

void *memmove(void *dest, const void *src, size_t n);

In der Linux-Handbuchseite heißt es:

RÜCKGABEWERT
Die Funktion memmove() gibt einen Zeiger auf dest zurück.

Warum ist die Funktion nicht einfach definiert als void memmove(…) wenn es immer einen der Eingabeparameter zurückgibt? Kann der Rückgabewert unterschiedlich sein von dest?

Oder ist der Rückgabewert wirklich immer dest und es wird nur gemacht, um die Funktion auf kreative Weise zusammenstellen zu können?

  • Großartig, ich muss mein Mittagessen verschieben, um die Antwort darauf zu sehen … 🙂 Meine Vermutung ist, dass der letzte Satz von Ihnen der Fall ist.

    – Gsamaras

    12. Oktober 2016 um 13:31 Uhr


  • “… einen anderen Zeiger als dest zurückgeben?” –> Mit UB ist alles möglich, sonst nein.

    – chux – Wiedereinsetzung von Monica

    12. Oktober 2016 um 13:36 Uhr

  • Mögliches Duplikat: stackoverflow.com/questions/13720428/…

    – PP

    12. Oktober 2016 um 13:41 Uhr


Benutzeravatar von Sergey Kalinichenko
Sergej Kalinitschenko

memmove wird niemals etwas anderes als zurückgeben dest.

Rückkehr destim Gegensatz zu machen memmove void ist nützlich, wenn das erste Argument ein berechneter Ausdruck ist, da Sie damit vermeiden können, denselben Wert im Voraus zu berechnen und ihn in einer Variablen zu speichern. So können Sie in einer einzigen Zeile arbeiten

void *dest = memmove(&buf[offset] + copiedSoFar, src + offset, sizeof(buf)-offset-copiedSoFar);

was Sie sonst in zwei Zeilen tun müssten:

void *dest = &buf[offset] + copiedSoFar;
memmove(dest, src + offset, sizeof(buf)-offset-copiedSoFar);

  • Lassen Sie es nichts zurückgeben. Dies ist nicht Gegenstand dieser Funktion. Zeichenfolgenfunktionen geben einen Zeiger zurück, da der Zeiger auf O(N)-Weise berechnet wird (wenn ich mich darin irre, sollten Zeichenfolgenfunktionen auch keinen Zeiger zurückgeben).

    – usr

    12. Oktober 2016 um 20:16 Uhr

  • Dies ist ein ziemlich schwaches Argument, IMO. Wenn Sie mir das erste Beispiel in einer Codeüberprüfung gezeigt haben, würde ich Sie bitten, es in das zweite umzuwandeln. Warum ist es memmoveist es Ihre Aufgabe, Ihnen beim Erstellen von Einzeilern zu helfen? Ein viel besserer Rückgabewert wäre gewesen dest + ndenn dann könnte man Dinge aneinander reihen: dest = memcpy(dest, ...); dest = memcpy(dest.. ); etc.

    – GManNickG

    13. Oktober 2016 um 0:45 Uhr

  • @GManNickG Für mich liegt ein großer Teil der Schönheit von C in seinen erstaunlichen Einzeilern. Mein persönlicher Favorit ist while ((*dest++ = *src++)); zum Kopieren von Strings. Als ich das Semikolon am Ende sah, war ich süchtig! Ich stimme Ihnen zu, dass es viel sinnvoller wäre, das Ende des Puffers zurückzugeben, anstatt seinen Anfang.

    – Sergej Kalinitschenko

    13. Oktober 2016 um 1:46 Uhr

  • @dasblinkenlight Ich würde es eher obskur als erstaunlich nennen, zumindest für andere als C-Programmierer. Wenn ich Zeichenfolgen in einer Zeile kopieren möchte, verwende ich lieber einfach strcpy ohnehin.

    – Malcolm

    13. Oktober 2016 um 9:27 Uhr

  • Die Einzeiler in C sind faszinierend und irgendwie nett, aber sie sollten als Kunst betrachtet werden, nicht als produktionswürdiger Code.

    – usr

    13. Oktober 2016 um 14:53 Uhr

Benutzeravatar von Sourav Ghosh
Sourav Ghosh

Gem C11Kapitel §7.24.2.1 und §7.24.2.2

void *memcpy(void * restrict s1, const void * restrict s2, size_t n);

[…] Das memcpy Funktion gibt den Wert von zurück s1.

und,

void *memmove(void *s1, const void *s2, size_t n);

[…] Das memmove Funktion gibt den Wert von zurück s1.

Die Funktionen geben also immer den Zeiger auf den Zielpuffer zurück, das ist beabsichtigt.

Kommen wir nun zum warum Teilweise sind viele Funktionen auf diese Weise entworfen worden, um eine Verkettung von Funktionsaufrufen zu ermöglichen. So können Sie telefonieren memmove() als Argument für eine andere Funktion, wobei der kopierte Wert (dh der Zeiger auf dest) wird von einigem Nutzen sein.

Sie können zum Beispiel die kürzere schreiben

 puts(memmove(dest_buffer, src_buffer, welcome_message_size));

statt der längeren

 memmove(dest_buffer, src_buffer, welcome_message_size);
 puts(dest_buffer);

AnT steht mit Russlands Benutzer-Avatar
AnT steht zu Russland

Das Idiom, den genauen Wert eines der Argumente (vom Zeigertyp) zurückzugeben, existiert, um “verkettete” Funktionsaufrufe zu unterstützen (siehe auch strcpy, strcat etc). Es ermöglicht Ihnen, sich wiederholenden Code als einzelne Ausdrucksanweisung zu schreiben, anstatt ihn in mehrere Anweisungen aufzuteilen. Zum Beispiel

char buffer[1024];
printf("%s\n", strcat(strcat(strcpy(buffer, "Hello"), " "), "World"));

struct UserData data_copy;
some_function(memcpy(&data_copy, &original_data, sizeof original_data));

Auch wenn Ihnen diese Art der Organisation von Code nicht gefällt und Sie es vorziehen, dasselbe über mehrere Anweisungen zu tun, ist der Mehraufwand für die Rückgabe von an [unnecessary] Zeigerwert ist praktisch nicht vorhanden.

Man kann sogar sagen, dass der Wert dieser Redewendung nach der Einführung von etwas gestiegen ist zusammengesetzte Literale im C99. Bei zusammengesetzten Literalen erlaubt genau diese Redewendung, denselben Code zu schreiben, ohne eine benannte Zwischenvariable einzuführen

printf("%s\n", strcat(strcat(strcpy((char [1024]) { 0 }, "Hello"), " "), "World!"));

some_function(memcpy(&(struct UserData) { 0 }, &original_data, sizeof original_data));

was sinnvoll ist, da diese benannte Variable in den meisten Fällen nur von kurzer Dauer sein soll, danach nicht mehr benötigt wird und nur den Namensraum unübersichtlich macht.

  • Ich mache nicht viel mit C, würde es aber nicht tun sizeof data_copy in Ihrem Beispiel für zusammengesetzte Literale müssen sein sizeof original_dataseit data_copy existiert nicht mehr?

    – Pokechu22

    12. Oktober 2016 um 17:45 Uhr

  • Natürlich wird das Beispiel mit strcat brillant ineffizient sein, da jede strcat-Operation damit beginnt, das Ziel zu scannen, um das Nullbyte zu finden, dann die neuen Daten zu verketten und dann die zurückzugeben Anfang des Ziels, sodass der nächste Anruf sowohl die alten als auch die neuen Daten durchsuchen muss, um die neue Position des Nullbytes zu finden.

    – Superkatze

    12. Oktober 2016 um 22:22 Uhr

  • @supercat: Ja, das kann man wahrscheinlich mit Sicherheit sagen strcat ist eine nutzlose Funktion. Es wird in meiner Antwort zu rein illustrativen Zwecken verwendet.

    – AnT steht zu Russland

    12. Oktober 2016 um 22:45 Uhr

1395680cookie-checkKönnen memcpy oder memmove einen anderen Zeiger als dest zurückgeben?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy