Why is there no bit shift left << a shift beyond 31 for a long internal data type?

I want to use the following code in my program, but it will not allow me to shift my 1 by 31. sizeof(long int) displays 8, so that does not mean that I can leave the shift to 63?

 #include <iostream> using namespace std; int main(){ long int x; x=(~0 & ~(1<<63)); cout<<x<<endl; return 0; } 

Compilation displays the following warning:

left shift count >= width type [enabled by default] x=(~0 & ~(1<<63)) ; ^ and the output is -1. If I left the shifted 31 bits, I would get 2147483647, as expected from int. I expect all bits except the MSB to be turned on, thus displaying the maximum value that the data type can store.

+7
source share
5 answers

Although your x is of type long int , 1 not. 1 is int , so 1<<63 really undefined.

Try (static_cast<long int>(1) << 63) or 1L << 63 , as suggested by Wojtek.

+7
source

You cannot use 1 (int by default) to move it outside of int.

A simpler way to get "all bits except MSB enabled" for a specific data type

 #include <iostream> #include <limits> using namespace std; int main(){ unsigned long int max = std::numeric_limits<unsigned long int>::max(); unsigned long int max_without_MSB = max >> 1; cout<< max_without_MSB <<endl; return 0; } 

Note the unsigned type. Without numeric_limits :

 #include <iostream> using namespace std; int main() { long int max = -1; unsigned long int max_without_MSB = ((unsigned long int)max) >> 1; cout << max_without_MSB << endl; return 0; } 
+3
source

First, let me say a few things about the shift, which is the source of your problem:

There is no guarantee that long int actually has a width of 64 bits.

The most common way I can think of is to use std::numeric_limits :

 static_cast<long int>(1) << (std::numeric_limits<long int>::digits - 1); 

Now you can even make this template function constexpr:

 template <typename Integer> constexpr Integer foo() { return static_cast<Integer>(1) << (std::numeric_limits<Integer>::digits - 1); } 

Thus, replacing the shift with static_cast<long int>(1) << (std::numeric_limits<long int>::digits - 1) will fix your problem, however there is a much better way:

std::numeric_limits includes a bunch of useful things, including:

 std::numeric_limits<T>::max(); // the maximum value T can hold std::numeric_limits<T>::min(); // the minimum value T can hold std::numeric_limits<T>::digits; // the number of binary digits std::numeric_limits<T>::is_signed(); // well, do I have to explain? ;-) 

For a complete list, see cppreference.com . You should prefer the tools provided by the standard library, because it will most likely have fewer errors, and other developers will immediately find out.

+2
source

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.

+2
source

The default data type for a numeric value in C is an integer unless explicitly specified.

Here you must enter cast 1 as long int , which would otherwise be int.

+1
source

All Articles