LONG_MAX -1 是在 64 位机器上吗?

Is LONG_MAX -1 in 64bit machine?

我发现LONG_MAX(9223372036854775807)在64位机的long类型变量上其实是这样保存的

Hex: 0xffff ffff ffff ffff ffff ffff ffff ffff

Bin: 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

据我所知,最高有效位用作有符号位。

而9223372036854775807在Windows计算器中的变化如下。

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

所以,恕我直言,LONG_MAX 应该保存如下

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

长变量是否被视为无符号值?

我注意到有人问我是如何发现这种情况的。

我在下面的代码中找到了这种情况。

#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;
}

其实我并没有使用LONG_MAX这个宏,而是在执行程序的时候静态使用了9223372036854775807这个值

我检查了该值作为 0x7fff 是安全的...使用 gdb 如下所示

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) 

即使我没有使用 LONG_MAX 宏,值 9223372036854775807 与 LONG_MAX 宏相同。

所以,我认为它应该保存为 0x7fff ...就像使用 LONG_MAX。

9223372036854775807就是0b 0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111,这是10后面跟着631s(1位+63位=64位),前导0表示一个正数的补码表示,这是最常见的有符号整数表示, 当假设正号由 0 位标记时,9223372036854775807 在有符号整数的符号 + 值表示中也是 0b 0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111

如果有符号整数的符号+值表示中的正号由1位标记,则LONG_INT_MAX =9223372036854775807实际上存储为0xffff ffff ffff ffff0b1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 但是这种情况很少见

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

有符号整数有多种格式,最常见的是 -9223372036854775807 的二进制补码(注意 (-) 符号)这是 0b1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001,前导 1 表示二进制补码表示中的负数

您忘记包含 <stdlib.h>,因此您的编译器发出警告,例如 warning: implicit declaration of function ‘strtol’

当您选择忽略警告时,编译器只是将 strtol 的 return 值视为 int(32 位值)而不是 long(64位值),因此发生从 64 位到 32 位的截断,因此存在差异。

示范:

#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); 
}

运行 这有和没有取消注释 #include <stdlib.h>

结论:始终将包含“隐含”一词的警告视为错误。