Why does array_push_back need three parameters? Couldn't the macro just use size_of on the second param?
data_type *pp = arr->data;\
this is expanded to something like (when data_type is double): double *pp = arr->data;
You can get rid of the third parameter. Just store the size of the data type in the container struct and use memcpy. Something like this (probably slower than the original): char *pp = arr->data;\
memcpy(pp + (size - 1) * arr->size_of_data, &(x), arr->size_of_data);\