En fait, je suggère d'utiliser les deux.
Si vous voulez quelque chose qui est définitivement 32-bits non signés, utilisez uint32_t. Par exemple, si vous implémentez un "struct" pour représenter un objet externe dont la spécification définit un de ses champs comme étant de 32 bits non signés.
Si vous voulez quelque chose qui correspond à la "taille de mot naturelle de la machine", utilisez int ou unsigned int. Par exemple :
for (int i = 0 ; i < 200 ; ++i)
// stuff
La "taille de mot naturelle de la machine" vous donnera les meilleures performances, tant sur les processeurs d'aujourd'hui que sur ceux de demain.
Utilisez "char" si vous voulez dire "caractère" ; "char" ou "unsigned char" si vous voulez dire "octet". Le C/C++ vous permet d'accéder aux octets d'un objet arbitraire via "char *", et rien d'autre, à proprement parler.
Utilisez uint8_t ou int8_t si vous voulez spécifiquement un entier de 8 bits, comme uint32_t.