If upcasting doesn't gain you any bits (there's no guarantee that sizeof(long)>sizeof(int) in C), you can use conditions like the ones below to compare and check for overflow—upcasting is almost certainly faster if you can use it, though.
#if !defined(__GNUC__) || __GNUC__<2 || (__GNUC__==2 && __GNUC_MINOR__<96)
# define unlikely(x) (x)
#else
# define unlikely(x) (__extension__ (__builtin_expect(!!(x), 0)))
#endif
/* ----------
* Signed comparison (signed char, short, int, long, long long)
* Checks for overflow off the top end of the range, in which case a+b must
* be >c. If it overflows off the bottom, a+b < everything in the range. */
if(a+b>c || unlikely(a>=0 && b>=0 && unlikely(a+b<0)))
...
/* ----------
* Unsigned comparison (unsigned char, unsigned short, unsigned, etc.)
* Checks to see if the sum wrapped around, since the sum of any two natural
* numbers must be >= both numbers. */
if(a+b>c || unlikely(a+b<a))
...
/* ----------
* To generate code for the above only when necessary: */
if(sizeof(long)>sizeof(int) ? ((long)a+b>c)
: (a+b>c || unlikely(a>=0 && b>=0 && unlikely(a+b<0)))
...
Great candidates for macros or inline functions. You can pull the "unlikely"s if you want, but they can help shrink and speed up the code GCC generates.