Generic things are rarely efficient, the most optimal code tends to be specialized and tailored to specific hardware and/or the kind of data its operating on.
std::vector (which is a really inefficient way of doing dynamic arrays btw) can be cleanly implemented with macros (see stb stretchy buf) or by splitting the element data from the housekeeping data:
int append(void *arr, size_t elemsize, size_t *capacity, size_t *size, const void *items_to_add, size_t num_items_to_add);