static_cast può fare cast aritmetici, cast tra puntatori/riferimenti nella stessa gerarchia di classi e un po' di altre cose; trovi tutti i dettagli nello standard (§5.2.9) (nota comunque che i cast tra puntatori a classi polimorfiche vanno fatti con dynamic_cast se non c'è la certezza assoluta che il cast sia valido).
Per fare una conversione "selvaggia" tra puntatori e interi (o tra puntatori di tipi incompatibili), invece, bisogna usare il reinterpret_cast; l'idea del reinterpret_cast è che il risultato del cast in sé non è ben definito, ma se uno fa un reinterpret_cast in un verso e poi nell'altro il risultato è valido (a patto che il tipo intermedio sia di dimensioni adeguate).
Ovvero, se faccio int * => DWORD => int * riottengo lo stesso puntatore (se sizeof(DWORD)>=sizeof(int *)); d'altra parte, se faccio int * => char => int * (in cui, salvo piattaforme strane, sizeof(char)<sizeof(int *)) con ogni probabilità non riotterrò il mio puntatore originale.