When the left shift does not coincide with multiplication by 2

I tried to exercise KR 2.1 - to determine the range of long variables by direct calculation.

 #include <stdio.h> #include <limits.h> int main() { unsigned short long_bits = sizeof( long ) * CHAR_BIT; printf( "LONG_MAX = %ld\n", ( 1L << ( long_bits - 1 ) ) - 1 ); printf( "LONG_MIN = %ld\n", ( -1 ) * ( 1L << ( long_bits - 1 ) ) ); printf( "ULONG_MAX (1) = %lu\n", ( 1UL << long_bits ) - 1 ); // doesn't work printf( "ULONG_MAX (2) = %lu\n", 2*( 1UL << ( long_bits - 1 ) ) - 1 ); // work printf( "\n" ); } 
  • ULONG_MAX (1) = 0 incorrect, because I assume left shift overflow.
  • ULONG_MAX (2) = 18446744073709551615 seems correct, replacing the last left shift by multiplying by 2.

So it looks like the left shift operator is suffering from overflow, but there is no multiplication? Does this intermediate calculation 2*( 1UL << ( long_bits - 1 ) ) do more to some type than long ? In my machine, long and long long exactly the same (8 bytes).


Edit: As Lundin noted, all that is required for ULONG_MAX is printf( "ULONG_MAX = %lu\n", ~0L );

Using a left shift in this case caused UB and multiplying by 2 is also potentially UB (although result 2 looks right).

+5
source share
1 answer

The behavior of a left shift of a value is determined only if the amount you shift to the left is less than the size of this type. Therefore, 1UL << long_bits is undefined behavior, and anything can happen, including dæmons flying out of your nose.

Let n be the number of bits in the type we are working with. In practice, depending on the platform, in this case there are two behaviors: either any left shift by n or more produces 0 (as the entire bit pattern is shifted), or a left shift decreases modulo n , so the left shift at points n behaves like a left shift in places of 0 , giving 1UL << 0 or 1 .

+4
source

Source: https://habr.com/ru/post/1238366/


All Articles