Sie können auch diese Verwendung von memmove
gesehen in Git 2.14.x (Q3 2017)
Ver Commit 168e635 (16. Juli 2017), und 1773664 übertragen , f331ab9 übertragen , festlegen 5783980 (15 Jul 2017) von René Scharfe ( rscharfe
) .
(Zusammengefasst von Junio C. Hamano -- gitster
-- en 32f9025 übertragen , 11. August 2017)
Es verwendet eine Hilfsmakro MOVE_ARRAY
die die Größe berechnet auf der Grundlage der angegebenen Anzahl von Elementen für uns und unterstützt NULL
Zeiger, wenn diese Zahl Null ist.
Rohe memmove(3)
Anrufe mit NULL
kann den Compiler dazu veranlassen, später (übereifrig) zu optimieren NULL
Kontrollen.
MOVE_ARRAY
fügt ein sicheres und bequemes Hilfsmittel zum Verschieben von sich möglicherweise überschneidenden Bereichen von Array-Einträgen hinzu.
Es leitet die Elementgröße ab, multipliziert automatisch und sicher, um die Größe in Bytes zu erhalten, führt eine grundlegende Typsicherheitsprüfung durch, indem es Elementgrößen vergleicht und im Gegensatz zu memmove(3)
es unterstützt NULL
Zeiger, wenn 0 Elemente verschoben werden sollen.
#define MOVE_ARRAY(dst, src, n) move_array((dst), (src), (n), sizeof(*(dst)) + \
BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
static inline void move_array(void *dst, const void *src, size_t n, size_t size)
{
if (n)
memmove(dst, src, st_mult(size, n));
}
Beispiele :
- memmove(dst, src, (n) * sizeof(*dst));
+ MOVE_ARRAY(dst, src, n);
Es verwendet die Makro BUILD_ASSERT_OR_ZERO
die eine Abhängigkeit zur Erstellungszeit behauptet, als Ausdruck (mit @cond
ist die Bedingung zur Kompilierzeit, die wahr sein muss).
Die Kompilierung schlägt fehl, wenn die Bedingung nicht erfüllt ist oder vom Compiler nicht ausgewertet werden kann.
#define BUILD_ASSERT_OR_ZERO(cond) \
(sizeof(char [1 - 2*!(cond)]) - 1)
Beispiel:
#define foo_to_char(foo) \
((char *)(foo) \
+ BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
8 Stimmen
Mathematisch gesehen ist die Schnittmenge von zwei leeren Mengen leer.
0 Stimmen
Ich wollte für Sie prüfen, was (x)libC für Sie tut, aber da es ist asm (elibc/glibc hier), es ist ein bisschen zu kompliziert für einen frühen Morgen :)
0 Stimmen
Warum würde Sie das tun? Übrigens sind überlappende Speicherbereiche nicht der einzige Grund für UB mit
memcpy
.21 Stimmen
+1 Ich liebe diese Frage, weil sie ein so seltsamer Sonderfall ist und weil ich denke, dass
memcpy(0,0,0)
ist eines der seltsamsten Stücke von C-Code, die ich je gesehen habe.3 Stimmen
@eq Wollen Sie das wirklich wissen, oder wollen Sie damit sagen, dass es keine Situationen gibt, in denen Sie es wissen wollen? Haben Sie in Betracht gezogen, dass der eigentliche Anruf z. B. lauten könnte,
memcpy(outp, inp, len)
? Und dass dies in einem Code auftreten könnte, in demoutp
yinp
werden dynamisch zugewiesen und sind zunächst0
? Dies funktioniert z. B. mitp = realloc(p, len+n)
cuandop
ylen
sind0
. Ich selbst habe eine solchememcpy
Aufruf - obwohl es technisch gesehen UB ist, bin ich noch nie auf eine Implementierung gestoßen, bei der es kein No-Op ist, und ich erwarte es auch nicht.9 Stimmen
@templatetypedef
memcpy(0, 0, 0)
ist höchstwahrscheinlich dazu gedacht, einen dynamischen, nicht statischen Aufruf darzustellen ... d.h. diese Parameterwerte müssen keine Literale sein.0 Stimmen
@eq, @templatetypedef: Es handelt sich nicht um wörtliche, sondern um dynamische Werte... in einer Software eines Drittanbieters :/
0 Stimmen
@Jim Balter: Natürlich habe ich das (darüber nachgedacht). Wann immer ich C verwende, versuche ich, portables (d.h. wohldefiniertes) C zu schreiben, auch wenn ich ein paar mehr Konditionale schreiben muss - es ist unwahrscheinlich, dass sie ein Leistungsengpass sind (und ich würde sie nur entfernen, wenn sie es wären, denn sie zu schreiben ist nicht so schwer), und der einzige Weg, das herauszufinden, ist nun, es herauszufinden. Ob sie eines Tages "den Tag retten" werden oder nicht, ist eigentlich irrelevant.
1 Stimmen
Im Gegensatz zu C++ behandelt C null nicht als Zeiger auf ein Array. (Das ist sehr seltsam.)
0 Stimmen
Verwandt: youtu.be/I8QJLGI0GOE?t=2100