Your name is misleading; a long can shift beyond 31 if a long really large. However, your code shifts 1 , which is int .
In C ++, the type of expression is determined by the expression itself. The expression XXXXX is of the same type independently; if you later go double foo = XXXXX; , this does not mean that XXXXX is double - it means that the conversion comes from any XXXXX , to double .
If you want to move left to left, then do it explicitly, for example. 1L << 32 or ((long)1) << 32 . Please note that long size varies between platforms, so if you do not want your code to be interrupted when it starts on another system, you will have to take additional measures, such as using fixed-width types or transferring to CHAR_BIT * sizeof(long) - 1 .
There is another problem with your intended code: 1L << 63 causes undefined behavior if long is 64-bit or less. This is due to the whole sign overflow; the left shift is defined in the same way as repeated multiplication by two, therefore the attempt to “shift to the sign bit” causes overflow.
To fix this, use unsigned types where it's normal to go to MSB, for example. 1ul << 63 .
Technically, there is another problem that ~0 does not do what you want if you are not using a system with two add-ons, but these days it is pretty safe to ignore this case.
Looking at your overall intention with long x = ~0 & ~(1 << 63) . A shorter way to write this:
long x = LONG_MAX;
which is defined by <climits> . If you want 64-bit on all platforms, then
int64_t x = INT64_MAX;
NB. If you are not going to work with negative values, use unsigned long x and uint64_t respectively.