I attempted KR exercise 2.1 - 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
is wrong because the left shift overflow I suppose.ULONG_MAX (2) = 18446744073709551615
seems correct by replacing the last left shift with a multiply by 2.So it appears that left shift operator suffers from overflow, but multiplication does not? Does this intermediate calculation 2*( 1UL << ( long_bits - 1 ) )
promote to some type more than long
? In my machine, long
and long long
are exactly the same ( 8 Bytes ).
Edit:
As Lundin pointed out, all needed for ULONG_MAX
is printf( "ULONG_MAX = %lu\n", ~0L );
Using left shift in this case caused UB, and multiply by 2 is potentially UB, too (although result of case 2 looks correct).
The behaviour of left-shifting a value is only defined if the amount you are left-shifting by is less than the size of the type. Therefore, 1UL << long_bits
is undefined behaviour 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 platform, there are two behaviours that happen in this case: Either, any left-shift by n
or more produces 0
(as the whole bit-pattern is shifted out), or the left-shift is reduced modulo n
, so a left-shift by n
places behaves like a left shift by 0
places, yielding 1UL << 0
or 1
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With