2010-09-20 5 views
70

Muss ich Fälle behandeln, wenn ich mit memmove()/memcpy() als Grenzfälle actully nichts zu bewegen/kopierenKann ich memcpy() und memmove() mit "Anzahl der Bytes" auf Null setzen?

int numberOfBytes = ... 
if(numberOfBytes != 0) { 
    memmove(dest, source, numberOfBytes); 
} 

oder sollte ich nenne nur die Funktion ohne

int numberOfBytes = ... 
memmove(dest, source, numberOfBytes); 

Überprüfung Ist das Prüfungs im ehemaligen schnipsel notwendig?

+6

Frage erinnert mich ein bisschen auf Nullzeiger auf Funktionen wie kostenlos zu überprüfen. Nicht notwendig, aber ich würde einen Kommentar abgeben, um zu zeigen, dass Sie darüber nachgedacht haben. – Toad

+10

@Toad: Welchen Zweck erfüllt das, außer den Code zu überladen?Wenn ich jemandes Code lese, muss ich nicht wissen, dass der ursprüngliche Programmierer "über diese Operation nachdachte, die eigentlich nicht notwendig ist, aber weil es unnötig ist, habe ich es nicht gemacht". Wenn ich sehe, dass ein Zeiger freigegeben wird, weiß ich, dass es Null sein darf, also muss ich die Gedanken des ursprünglichen Programmierers zum Thema "Soll ich nach Null suchen" nicht kennen. Und das gleiche gilt für das Kopieren von 0 Bytes mit 'memcpy' – jalf

+5

@jalf: die Tatsache, dass es eine Frage auf stackoverflow ist, macht es etwas, das Leute zweifeln. Das Hinzufügen eines Kommentars kann Ihnen vielleicht nicht helfen, könnte aber jemandem mit weniger Wissen helfen – Toad

Antwort

102

Vom C99-Standard (7.21.1/2):

Wo ein als size_t n erklärt Argument für eine Funktion der Länge des Arrays spezifiziert, kann n den Wert Null auf einen Aufruf, dass Funktion. Sofern nicht ausdrücklich anders angegeben, müssen die Zeigerargumente bei einem solchen Aufruf ansonsten in der Beschreibung einer bestimmten Funktion in diesem Abschnitt gültige Werte haben, wie in 7.1.4 beschrieben. Bei einem solchen Aufruf findet eine -Funktion, die ein Zeichen findet, kein Vorkommen, eine Funktion, die zwei Zeichenfolgen vergleicht, gibt Null zurück, und eine Funktion, die Zeichen kopiert, kopiertZeichen.

Also die Antwort ist nein; Die Überprüfung ist nicht notwendig (oder ja; Sie können Null übergeben).

+0

Würde ein Zeiger für eine solche Funktion als "gültig" betrachtet, wenn er auf den Ort nach dem letzten Element eines Arrays zeigt? Solch ein Pointer konnte nicht legitim deferenziert werden, aber man könnte sicher einige andere pointer-ische Dinge wie Subtrahieren von einem davon machen. – supercat

+0

@supercat: Ja, ein Zeiger, der über das Ende eines Arrays hinausweist, ist für Zeigerarithmetik mit anderen Zeigern innerhalb (oder nach dem Ende von) dieses Arrays gültig, aber nicht dereferenzierbar. –

+0

@MikeSeymour: Sollte das Zitat nicht eine gegenteilige Antwort implizieren: Die Überprüfung ist notwendig und Sie können Null mit Nullzeigern nicht übergeben? – neverhoodboy

2

Nein, die Überprüfung ist nicht notwendig. Sich auf Null zu verlassen, ist meiner Meinung nach in Ordnung und sehr vernünftig. Es könnte einen Kommentar wert sein.

+0

Nicht unbedingt. Eine sehr häufige Verwendung wäre das Einfügen und Löschen von Arrays, die keine Char-Arrays sein könnten. Jede Array-Verwendung kann eine Bewegung von null Länge als natürlichen Fall haben, und es ist schön, dies nicht in Sonderfällen zu tun. –

12

Die Dokumentation von memmove und memcpy sagt dies:

Die Funktion für jedes abschließendes Nullzeichen überprüft nicht in Quelle - es immer Kopien genau num Bytes.

Die opengroupdocumentation sagt im Grunde die gleiche Sache.

So gegeben, dass es Kopien „genau num Bytes“, es Null-Bytes kopieren, wenn num = 0, und somit sollte es nicht erforderlich sein, dies als Sonderfall zu behandeln.

+1

Wenn es immer genau * num * Bytes kopiert, hat es kein Problem, genau 0 Bytes zu kopieren. :) –

+1

@qrdl: Es tut, es beantwortet die Frage "muss ich' num = 0 'als Sonderfall behandeln? ". – You

+1

OP hat nach Randbedingungen gefragt, daher ist es nicht angebracht, die allgemeine Antwort anzugeben. 'num = 0' Bit ist nach dem Editieren erschienen. – qrdl

5

Wie von @You angegeben, gibt der Standard an, dass memcpy und memmove diesen Fall ohne Probleme behandeln sollten. da sie in der Regel irgendwie wie

void *memcpy(void *_dst, const void *_src, size_t len) 
{ 
    unsigned char *dst = _dst; 
    const unsigned char *src = _src; 
    while(len-- > 0) 
     *dst++ = *src++; 
    return _dst; 
} 

implementiert werden, sollten Sie nicht einmal eine Performance Penalität anders als den Funktionsaufruf haben; Wenn der Compiler intrinsics/inlining für solche Funktionen unterstützt, kann die zusätzliche Prüfung sogar dazu führen, dass der Code ein kleines bisschen langsamer wird, da die Überprüfung bereits in der while-Phase erfolgt.

+0

Ich würde denken, dass diese Funktion wahrscheinlich in Assembly gemacht wird, wo Sie Speicherübertragungen viel besser als in c – Toad

+0

* "irgendwie wie" * :) Eigentlich fast alle Implementierungen, die ich gesehen habe, sind in Assembly, und versuchen, die meisten zu kopieren die Bits benutzen die native Wortgröße (zB uint32_t auf x86), aber das ändert nichts an der Substanz der Antwort: Es ist eine * while * -Schleife, die vor dem Start keine großen Berechnungen benötigt, also ist die Prüfung bereits erledigt. –

+5

-1, ist die typische Implementierung irrelevant, ob es zulässig ist, diese Funktionen (die möglicherweise nicht als C-Funktionen implementiert sind) mit einem Null-Argument aufzurufen. –

Verwandte Themen