c语言如何在内存中存储int?

How does c language store int in memory?

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

int main() {
    int *p_x = (int *)malloc(1 * sizeof(int));
    scanf("%d", p_x);

    for (int i = 0; i < 4; i++) {
        char *one_byte_slice = (((char *)(p_x)) + i);
        printf("slice : %d , value : %d\n", i, *one_byte_slice);
    }
    return 0;
}

当我输入正值时,它们对我来说似乎可以理解,但对于负值,我不太理解。

对于*p_x = 127

127
slice : 0 , value : 127
slice : 1 , value : 0
slice : 2 , value : 0
slice : 3 , value : 0

p_x  --->  0111 1111
           0000 0000
           0000 0000
           0000 0000

对于*p_x = 256

256
slice : 0 , value : 0
slice : 1 , value : 1
slice : 2 , value : 0
slice : 3 , value : 0

p_x  --->  0000 0000
           0000 0001
           0000 0000
           0000 0000

对于*p_x = -20

-20
slice : 0 , value : -20
slice : 1 , value : -1
slice : 2 , value : -1
slice : 3 , value : -1

p_x  --->  1001 0100
           1000 0001
           1000 0001
           1000 0001

对于*p_x = -256

-256
slice : 0 , value : 0
slice : 1 , value : -1
slice : 2 , value : -1
slice : 3 , value : -1

p_x  --->  0000 0000
           1000 0001
           1000 0001
           1000 0001

那么它是如何存储在内存中的定点数是以 2 的补码或其他方式存储的?

是的,我想我得到了答案。

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

int main() {
    int *p_x = (int *) malloc(1*sizeof(int));
    scanf("%d",p_x);

    for(int i=0;i<4;i++) {
        unsigned char *one_byte_slice = ( ((unsigned char *)(p_x)) + i);
        printf("slice : %d , value : %hhx\n",i,*one_byte_slice);
    }
    return 0;
}

当我尝试 %hhxunsigned char * 时,它显示 2's 负值的补码。

-1
slice : 0 , value : ff
slice : 1 , value : ff
slice : 2 , value : ff
slice : 3 , value : ff


p_x  --->  1111 1111
           1111 1111
           1111 1111
           1111 1111
-3
slice : 0 , value : fd
slice : 1 , value : ff
slice : 2 , value : ff
slice : 3 , value : ff

p_x  --->  1111 1101
           1111 1111
           1111 1111
           1111 1111

是的,所以结论是它以 2's 补码格式存储。

这称为低端编码。整数的各个位片按从最低有效到最高有效的顺序存储在连续的字节单元中。 您的整数以二进制形式表示为:

0000 0000 0000 0000 0000 0000 0111 1111

(我使用 space 来分隔每组四位)。 每个字节从最低有效的八位组到最高有效字节地址,从右上方开始存储:

Addr.  Value.
0000: 0111 1111
0001: 0000 0000
0002: 0000 0000
0003: 0000 0000

还有另一种方法,叫做big-endian,就是把字节倒过来存储,有的机器是这样做的:

(Big-endian)
Addr.  Value.
0000: 0000 0000
0001: 0000 0000
0002: 0000 0000
0003: 0111 1111

还有其他方法可以做到,但今天的计算机通常使用这两种方法之一。

在负数的情况下,解决方案在于考虑负数和正数,以便可以在不必使用备用电路的情况下完成加法和减法。所以数字被分成两半,最高有效位的那些代表负数......所以数字被表示(为了简洁我只使用四位):

1000: -8
1001: -7
1010: -6
1011: -5
1100: -4
1101: -3
1110: -2
1111: -1
0000: 0
0001: 1
0010: 2
0011: 3
0100: 4
0101: 5
0110: 6
0111: 7

32 位结果相同,但扩展到 32 位...这使得所有小负数的所有最高有效位等于 1

1000 0000 0000 0000: -2147483648
1000 0000 0000 0001: -2147483647
...
1111 1111 1111 1101: -3
1111 1111 1111 1110: -2
1111 1111 1111 1111: -1
0000 0000 0000 0000: 0
0000 0000 0000 0001: 1
...
0111 1111 1111 1100: 2147483644
0111 1111 1111 1101: 2147483645
0111 1111 1111 1110: 2147483646
0111 1111 1111 1111: 2147483647

这样加法就是在前面的 table 中向下跳跃,而减法则向上跳跃。这称为 two's complement 编码。