Your title is misleading; a long
can shift beyond 31
bits if a long
is indeed that big. However your code shifts 1
, which is an int
.
In C++, the type of an expression is determined by the expression itself. An expression XXXXX
has the same type regardless; if you later go double foo = XXXXX;
it doesn't mean XXXXX
is a double - it means a conversion happens from whatever XXXXX
was, to double
.
If you want to left-shift a long, then do that explicitly, e.g. 1L << 32
, or ((long)1) << 32
. Note that the size of long
varies between platforms, so if you don't want your code to break when run on a different system then you'll have to take further measures, such as using fixed-width types, or shifting by CHAR_BIT * sizeof(long) - 1
.
There is another issue with your intended code: 1L << 63
causes undefined behaviour if long
is 64-bit or less. This is because of signed integer overflow; left-shift is defined the same as repeated multiplication of two, so attempting to "shift into the sign bit" causes an overflow.
To fix this, use unsigned types where it is fine to shift into the MSB, e.g. 1ul << 63
.
Technically there is another issue in that ~0
doesn't do what you want if you are not on a 2's complement system, but these days it's pretty safe to ignore that case.
Looking at your overall intention with long x = ~0 & ~(1 << 63)
. A shorter way to write this is:
long x = LONG_MAX;
which is defined by <climits>
. If you wanted 64-bit on all platforms then
int64_t x = INT64_MAX;
NB. If you do not intend to work with negative values then use unsigned long x
and uint64_t
respectively.