-1

I'm trying to get the size limits of long long int with the following code:

int main()
{
    long long int from, to;
    printf("signed long long int: ");
    bytes=sizeof(long long int);
    bits = 8* bytes;
    from = -(1 << (bits-1));
    to =  (1 << (bits-1)) - 1;
    printf(" %d bytes from %lld to %lld\n", bytes, from, to);
}

the output is:

signed long long int:  8 bytes from -2147483648 to 2147483647

I expect it to be -9223372036854775808 to 9223372036854775807. What's wrong with the code above?

phuclv
  • 37,963
  • 15
  • 156
  • 475
user526427
  • 107
  • 1
  • 2
    that code does not compile.... – Mitch Wheat Nov 23 '19 at 03:16
  • 2
    Assigning the result of a calculation to a variable of type `long long int` will not result in the calculation being performed as `long long int`. Only the result will be converted. This is similar to how `double x = 1/2;` is `0` and not `0.5`. You should cast the operands to make sure the calculation is performed with the precision you want. – that other guy Nov 23 '19 at 03:19
  • so many duplicates: [bit shifting with unsigned long type produces wrong results](https://stackoverflow.com/q/31744305/995714), [left shift on 64 bits fail](https://stackoverflow.com/q/10048047/995714), [Compute signed long max value in C using bit shift](https://stackoverflow.com/q/41418472/995714), [How do I bit shift a long by more than 32 bits?](https://stackoverflow.com/q/2404439/995714), [bitwise left shift by 32](https://stackoverflow.com/q/40951434/995714), [Why doesn't left bit shift << shift beyond 31 for long int datatype?](https://stackoverflow.com/q/24117934/995714) – phuclv Nov 23 '19 at 04:54
  • Does this answer your question? [Is Shifting more than 32 bits of a uint64\_t integer on an x86 machine Undefined Behavior?](https://stackoverflow.com/questions/10499104/is-shifting-more-than-32-bits-of-a-uint64-t-integer-on-an-x86-machine-undefined) – phuclv Nov 23 '19 at 04:55

4 Answers4

3

What's wrong with the code above?

1 << (bits-1) is shifting the integer constant of type int outside its range and leads to integer overflow and undefined behavior.

You may want to consider shifting a long long rather than an int.

1LL << (bits-1)

Yet this too is integer overflow and undefined behavior as it shifts the 1 outside the long long range.

The result of E1 << E2 is E1 left-shifted E2 bit positions; ... If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined. C11dr §6.5.7 4


To portable find the range of long long, use LLONG_MIN, LLONG_MAX from <limit.h>.

#include <limit.h>

printf("%d bytes from %lld to %lld\n", bytes, LLONG_MIN, LLONG_MAX);

If long long lacks padding, (something very very common, by not required by C), the below will print the max value of long long.

#include <limit.h>
int main(void) {
  long long max;
  int bytes = sizeof(long long);
  int bits = CHAR_BIT * bytes;
  long long max_halfish = 1LL << (bits-2);
  long long max = (max_halfish - 1) + max_halfish;
  printf("max %lld\n", max);
}

min is simply (-max - 1) if we assume the very common 2's complement coding.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
2

You need to coerce the 1 before shifting, otherwise is it treated as an int constant:

#include <stdio.h>

int main()
{
    long long int from, to;
    printf("signed long long int: ");

    int bytes = sizeof(long long int);
    int bits = 8 * bytes;

    from = -(((long long)1) << (bits-1));
    to =  (((long long)1) << (bits-1)) - 1;

    printf(" %d bytes from %lld to %lld\n", bytes, from, to);
}

Or use the more readable 1LL as @phuclv pointed out.

Output:

signed long long int:  8 bytes from -9223372036854775808 to 9223372036854775807
Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
0

1 is an int literal, therefore 1 << (bits-1) is done in int type, which invokes undefined behavior since you're shifting more than the type's width. Use 1LL instead for a long long value

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
phuclv
  • 37,963
  • 15
  • 156
  • 475
0

1 is an integer constant, change to 1LL to get the result in long long int.

int main() {

  long long int from, to;
  int bytes,bits;

  printf("signed long long int: ");
  bytes=sizeof(long long int);
  bits = 8* bytes;
  from = -(1LL << (bits-1));
  to =  (1LL << (bits-1)) - 1;
  printf(" %d bytes from %lld to %lld\n", bytes, from, to);
}