Możesz również rozważyć to użycie memmove
widoczne w Git 2.14.x (Q3 2017)
Zobacz zatwierdzenie 168e635 (16 lipca 2017) i zatwierdzenie 1773664 , zatwierdzenie f331ab9 , zatwierdzenie 5783980 (15 lipca 2017) autorstwa René Scharfe ( rscharfe
) .
(Scalone przez Junio C Hamano - gitster
- w zatwierdzeniu 32f9025 , 11 sierpnia 2017)
Używa makra pomocniczego,MOVE_ARRAY
które oblicza rozmiar na podstawie określonej dla nas liczby elementów i obsługuje NULL
wskaźniki, gdy ta liczba wynosi zero. Wywołania
surowe memmove(3)
with NULL
mogą spowodować, że kompilator (zbyt chętnie) zoptymalizuje późniejsze NULL
sprawdzenia.
MOVE_ARRAY
dodaje bezpiecznego i wygodnego pomocnika do przenoszenia potencjalnie nakładających się zakresów wpisów tablicy.
Wychodzi z rozmiaru elementu, mnoży się automatycznie i bezpiecznie, aby uzyskać rozmiar w bajtach, przeprowadza podstawowe sprawdzenie bezpieczeństwa typu, porównując rozmiary elementów iw przeciwieństwie do memmove(3)
obsługuje NULL
wskaźniki, jeśli 0 elementów ma zostać przesuniętych.
#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));
}
Przykłady :
- memmove(dst, src, (n) * sizeof(*dst));
+ MOVE_ARRAY(dst, src, n);
Używa makra,BUILD_ASSERT_OR_ZERO
które zapewnia zależność od czasu kompilacji, jako wyrażenie (przy @cond
czym warunek czasu kompilacji musi być prawdziwy).
Kompilacja zakończy się niepowodzeniem, jeśli warunek nie jest prawdziwy lub nie może zostać oceniony przez kompilator.
#define BUILD_ASSERT_OR_ZERO(cond) \
(sizeof(char [1 - 2*!(cond)]) - 1)
Przykład:
#define foo_to_char(foo) \
((char *)(foo) \
+ BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))