Things are pretty bad when even on the most well-known platform, with a fairly straightforward implementation of two's complement integers, the answers are not intuitive.
Fortunately, with a few simple coding guidelines you can avoid major pitfalls.
1. Always do bit operations on unsigned types.
2. Never overflow signed types.
3. Always shift less than the type width. I can name architectures which implement large shifts in three distinct ways.
4. Know that most integers get promoted to int or unsigned, so you need an explicit cast to get 64 bits on most platforms. So 1ULL << 48 is okay, 1U << 48 is bad.
5. Treat unsigned int / unsigned long as contagious, just like float and double.