Вы также можете рассмотреть такое использование, memmove
увиденное в Git 2.14.x (3 квартал 2017 г.)
См. Commit 168e635 (16 июля 2017 г.) и зафиксировать 1773664 , зафиксировать f331ab9 , зафиксировать 5783980 (15 июля 2017 г.) Рене Шарфе ( rscharfe
) .
(Объединено Junio C Hamano - gitster
- в коммите 32f9025 , 11 августа 2017 г.)
Он использует вспомогательный макрос,MOVE_ARRAY
который вычисляет размер на основе указанного количества элементов для нас и поддерживает NULL
указатели, когда это число равно нулю.
Необработанные memmove(3)
вызовы с NULL
могут заставить компилятор (чрезмерно) оптимизировать последующие NULL
проверки.
MOVE_ARRAY
добавляет безопасный и удобный помощник для перемещения потенциально перекрывающихся диапазонов записей массива.
Он определяет размер элемента, автоматически и безопасно умножается, чтобы получить размер в байтах, выполняет базовую проверку безопасности типа, сравнивая размеры элементов, и в отличие от memmove(3)
него поддерживает NULL
указатели, если необходимо переместить 0 элементов.
#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));
}
Примеры :
- memmove(dst, src, (n) * sizeof(*dst));
+ MOVE_ARRAY(dst, src, n);
Он использует макрос,BUILD_ASSERT_OR_ZERO
который утверждает зависимость времени сборки, как выражение (с @cond
условием времени компиляции, которое должно быть истинным).
Компиляция завершится ошибкой, если условие не выполняется или не может быть оценено компилятором.
#define BUILD_ASSERT_OR_ZERO(cond) \
(sizeof(char [1 - 2*!(cond)]) - 1)
Пример:
#define foo_to_char(foo) \
((char *)(foo) \
+ BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))