Regehr clarifies this in the comments section: "Regarding signed overflow being defined or not, compiler developers generally draw a sharp distinction between undefined behavior and implementation-defined behavior. 32-bit ints, 2's complement, etc. are examples of the latter and signed overflow is an example of the former. A lot of developers do not draw such a sharp distinction, which is why I made a point of asking questions about this issue."
The funny part is that it's often better to use int exactly because of the undefined behavior on overflow. By signaling to the compiler that you don't intend to overflow a particular variable, it can optimize appropriately.
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.
If int is 32 bits and short is 16 bits, then converting unsigned short to int will always give a value in the range [0, 0xffff]. No exceptions.
In other words, please answer each question in the context of a C compiler whose implementation-defined characteristics include two's complement signed integers, 8-bit chars, 16-bit shorts, and 32-bit ints. The long type is 32 bits on x86, but 64 bits on x86-64 (this is LP64, for those who care about such things).