Is LONG_MAX -1 in 64bit machine?

Viewed 297

I found that LONG_MAX (9223372036854775807) is actually saved as below on the long type variable in the 64-bit machine.

Hex: 0xffff ffff ffff ffff ffff ffff ffff ffff

Bin: 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

As I know, the most significant bit is used as a signed bit.

And the 9223372036854775807 is changed as below in the Windows calculator.

Hex: 0x7fff ffff ffff ffff ffff ffff ffff ffff
Bin: 01111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

So, IMHO, the LONG_MAX should be saved as below

Hex: 0x7fff ffff ffff ffff ffff ffff ffff ffff
Bin: 01111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

Is a long variable considered as an unsigned value?

I noticed somebody ask how I found that situation.

I found the situation in the below code.

#include <stdio.h>
#include <limits.h>

int main(int argc, char *argv[])
{
        long a;

        a = strtol(argv[1], NULL, 0); 

        printf("%ld\n", a); 

        return 0;
}

Actually, I didn't use the LONG_MAX macro, but when I execute the program, I used 9223372036854775807 value statically.

I checked the value is safe as a 0x7fff ... with gdb like below

Reading symbols from test...done.
(gdb) b main
Breakpoint 1 at 0x40055c: file test.c, line 8.
(gdb) r 9223372036854775807
Starting program: ./test 9223372036854775807

Breakpoint 1, main (argc=2, argv=0x7fffffffe308) at test.c:8
8       a = strtol(argv[1], NULL, 0);
(gdb) n
10      printf("%ld\n", a);
(gdb) x/gt &a
0x7fffffffe218: 1111111111111111111111111111111111111111111111111111111111111111
(gdb) 

Even though I didn't use the LONG_MAX macro, the value 9223372036854775807 is the same as the LONG_MAX macro.

So, I think it should be saved as a 0x7fff ... like using LONG_MAX.

2 Answers

You forgot to include <stdlib.h>, therefore your compiler issued a warning such as warning: implicit declaration of function ‘strtol’.

As you chose to ignore the warning, the compiler simply considered the return value of strtol as int (32 bit value) instead of long (64 bit value), therefore a truncation from 64 bit to 32 bit occurs, hence the difference.

Demonstration:

#include <stdio.h>
#include <limits.h>
//#include <stdlib.h>

int main(int argc, char *argv[])
{
        long a, b;
        a = strtol("9223372036854775807", NULL, 0); 
        b = LONG_MAX;
        printf("%ld %ld\n", a, b); 
}

Run this with and whithout uncommenting #include <stdlib.h>.

Conclusion: always consider warnings containing the word "implicit" as errors.

9223372036854775807 is 0b 0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111, this is 1 0 followed by 63 1s (1 bit + 63 bit=64 bit), the leading 0 indicates a positive number in two's complement representation, that is the most common representation of signed integers, and 9223372036854775807 is also 0b 0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 in the sign + value representation for signed integers when assuming that a positive sign is marked by a 0-bit.

If a positive sign in the sign+value representation of a signed integer is marked by a 1-bit then LONG_INT_MAX =9223372036854775807 is actually stored as 0xffff ffff ffff ffff or 0b1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 however this would be very uncommon

(https://www.rapidtables.com/convert/number/decimal-to-binary.html?x=9223372036854775807)

There are multiple formats for signed integers, most common is two's complement for -9223372036854775807 (note the (-)-sign) this is 0b1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001, the leading 1 indicates a negative number in two's complement representation

Related