Hanno range di valori contenibili diversi (e quindi di fatto dimensioni in bit diverse); lo standard C99 garantisce come range minimi (§E ¶1):
short int => [-32767, +32767]
int => [-32767, +32767]
long int => [-2147483647, +2147483647]
ma in generale i limiti possono essere (e in genere sono) maggiori; viene comunque garantito che i range dell'uno siano compresi in quelli degli altri nel seguente ordine:
short int <= int <= long int
Inoltre si richiede che l'int sia l'intero di dimensioni "naturali" per la macchina su cui girerà il codice.
I limiti effettivi sono comunque definiti nell'header <limits.h> (per il C) o in <limits> (per il C++). In genere i limiti usati sulle macchine a 32 bit sono
short int => [-32768, +32767]
int => [-2147483648, +2147483647]
long int => [-2147483648, +2147483647]
Su quelle a 64 le cose variano; su Windows rimangono uguali per questioni di compatibilità, e il tipo che passa a 64 bit è il long long int. Su Linux invece in genere si passa il long a 64 bit.
Per finire, tieni conto che in genere in "short int" e "long int" l'"int" si omette, per cui di solito si scrive semplicemente long e short.
Per quanto concerne i float e i double, il concetto è analogo: i double in genere sono grandi il doppio, per cui c'è più spazio per la mantissa (maggiore precisione) e per l'esponente (si possono rappresentare valori più grandi e più piccoli).
In linea di principio, se non hai particolare esigenze usa gli int per gli interi e i double per i valori in virgola mobile; ottieni così un valore intero dal range adeguato per impieghi "normali" e sicuramente veloce, e valori in virgola mobile in buona precisione senza perdite sensibili in termini di prestazioni.