Ви також можете врахувати це використання, яке memmove
видно в Git 2.14.x (Q3 2017)
Див. Коміт 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))