Популярная основанная на макросах общая реализация вектора в C (https://github.com/eteran/c-vector/blob/master/vector.h) использует следующую схему памяти.
+------+----------+---------+
| size | capacity | data... |
+------+----------+---------+
^
| user pointer
Это позволяет использовать очень удобный API, где пользователь получает вектор, просто объявив указатель требуемого типа.
float *vf = NULL;
VEC_PUSH_BACK(vf, 3.0);
int *vi = NULL;
size_t sz = VEC_CAPACITY(vi);
Внутри, библиотека получает доступ к размеру и емкости, как это
#define VEC_CAPACITY(vec) \
((vec) ? ((size_t *)(vec))[-1] : (size_t)0)
Но разве это не нарушение строгого алиасинга?