普通は関数の引数が型を指定してユーザはそれに従うところを
とりあえずすべてアドレスで渡して、ユーザが自分で「そのアドレスは何を指しているか」を明示すると言うことだよ

va_list ap;
これの実体はただのアドレス
void *p; みたいなものだね
va_argの第二引数で型を指定しているが(int,double,char*)、その型のサイズに合わせてapを進めている
以下確認のコード

printf("[0x%08X] " , *(int*)ap); でapの中身が va_argで指定した型のサイズ分だけ移動しているのが分かると思う