The details are in C11, 6.3.1.8. To summarize:
If the unsigned type is equal-or-wider, the signed type is converted to unsigned.
Otherwise, if the signed type can hold all the values of the unsigned type, the unsigned type is converted to the signed type.
Otherwise, both are converted to the to the unsigned version corresponding to the signed type.
By "wider" I mean "has higher conversion rank".
Examples (on some particular architecture, e.g. sizeof(short) == 2
and sizeof(long) == sizeof(unsigned int) = 4
):
int + unsigned int => unsigned int (first rule, equal rank)
long + unsigned short => long (second rule, long contains u. short)
long + unsigned int => unsigned long (third rule)