I want to use the following code in my program but gcc won't allow me to left shift my 1 beyond 31.
sizeof(long int)
displays 8, so doesn't that mean I can left shift till 63?
#include <iostream>
using namespace std;
int main(){
long int x;
x=(~0 & ~(1<<63));
cout<<x<<endl;
return 0;
}
The compiling outputs the following warning:
left shift `count >= width` of type [enabled by default] `x=(~0 & ~(1<<63))`;
^
and the output is -1. Had I left shifted 31 bits I get 2147483647 as expected of int.
I am expecting all bits except the MSB to be turned on thus displaying the maximum value the datatype can hold.
Although your
x
is of typelong int
, the1
is not.1
is anint
, so1<<63
is indeed undefined.Try
(static_cast<long int>(1) << 63)
, or1L << 63
as suggested by Wojtek.Your title is misleading; a
long
can shift beyond31
bits if along
is indeed that big. However your code shifts1
, which is anint
.In C++, the type of an expression is determined by the expression itself. An expression
XXXXX
has the same type regardless; if you later godouble foo = XXXXX;
it doesn't meanXXXXX
is a double - it means a conversion happens from whateverXXXXX
was, todouble
.If you want to left-shift a long, then do that explicitly, e.g.
1L << 32
, or((long)1) << 32
. Note that the size oflong
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 byCHAR_BIT * sizeof(long) - 1
.There is another issue with your intended code:
1L << 63
causes undefined behaviour iflong
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:which is defined by
<climits>
. If you wanted 64-bit on all platforms thenNB. If you do not intend to work with negative values then use
unsigned long x
anduint64_t
respectively.The default datatype for a numeric value in C is integer unless explicitly mentioned.
Here you have to type cast the 1 as long int which would otherwise be an int.
First let me state a few things about the shift, which is the source of your problem:
There is no guarantee that
long int
is actually 64 bit wide.The most generic way I can think of is using
std::numeric_limits
:Now you can even make that a constexpr templated function:
So replacing the shift with
static_cast<long int>(1) << (std::numeric_limits<long int>::digits - 1)
will fix your issue, however there is a far better way:std::numeric_limits
includes a bunch of useful stuff, including:See cppreference.com for a complete list. You should prefer the facilities provided by the standard library, because it will most likely have fewer mistakes and other developers immediately know it.
You can't use 1 (int by default) to shift it beyond the int boundaries.
There's an easier way to get the "all bits except the MSB turned on" for a specific datatype
note the unsigned type. Without
numeric_limits
: