C语言-数据的储存

关于整形在内存中的存储

在创建变量的时候,是需要在内存中开辟空间的。空间的大小也是根据所创建的类型而定。

比如一个char类型的数据,就是一个字节,int类型的就是4个字节。

这里的一个空格表示一个字节

但是因为在内存中是用二进制来进行储存的,所以在内存中,整数都是换算成二进制来进行计算的

二进制又是0和1来组成的,计算方式是逢二进一。


原码、反码、补码

在计算机中又有三种二进制的表示方法,即原码、反码、补码

这三种表现方法均有符号位,和数值位两个部分。

符号位是在一个二进制数的最左边那一个数,那一位是0表示正数,是1表示负数。

比如:

10在二进制中是1010,如果是char类型的(char大小是八个比特位)00001010,最左边的是0,所以是正数。

-10在二进制中也是1010,但是最左边的那个数是1,char类型的话就是,10001010

正数的原码、反码和补码是一样。

比如:

15的原码:00001111

15的反码:00001111

15的补码:00001111

  1. 负数的原码

关于负数的原码、反码和补码就不一样了。

如果我们用负数的原码来进行计算,比如-1+1,这里的-1+1我们就用char八个bit位来计算把,int的比较大。

-1 的原码是:10000001

我们来进行加1,二进制逢二进一嘛,那就变成了:10000010

这 10000010 在二进制中因为有符号位的存在所以它是-2,但是-1+1不应该是0嘛,为什么会这样呢?

因为不能解决原码计算负数的问题,所以出现了反码。

  1. 负数的反码

反码的计算规则是:负数的反码是在原码的基础上,符号位不变,其他位数值按位取反,0变1,1变0。

然后我们再用负数的反码来计算。比如-5

-5的原码是10000101,转换成反码,符号位不变,其它位按位取反,就得到了:11111010

我们就用-5的反码来加2(正数的原、反、补相同),11111010 + 00000010 = 11111100 这串数字咱们在按位取反一下就得到了:10000011

10000011 计算下是:-3。这样就可以很好的计算负数了。

但是我们如果一直加,反码的-1+1再来计算11111110 + 00000001(正数的原码、反码、补码一样)

反码-1+1就得到了:11111111 再取反一下,符号位不变,其它位按位取反。就得到了:10000000 = “-0”?

咱们再对“-0”的反码进行加1,11111111 + 00000001 就得到了100000000,因为咱们是char类型的8bit位,这个有9个bit位,

多得咱们就丢掉了。所以最终就得到了00000000

但是这样不行啊,有-0 和 0 如果计算起来不就会多一个,计算的结果不就有1的误差了嘛。

因为有反码有-0 和 0 之间的误差,所以出现了补码。

  1. 负数的补码

补码:正数的补码不变,负数的补码是在反码的基础上加1

在计算机中的存储和计算都是用补码来进行的。

咱们就拿补码来计算一下吧。

比如-5 + 10

-5 的原码:10000101 反码:11111010 补码(反码加1等于补码):11111011

正数的原码、反码、补码相同所以

10 的原码:00001010 反码:00001010 补码:00001010

-5 的补码和 10 的补码相加就等于:100000101 因为是9个比特位(bit)所以多的就丢掉。

就得到了 00000101 这个数换算成十进制就是 5 。正数的原、反、补相同所以这个二进制位也是补码

这样补码就很好的解决了,反码计算有误差的问题了。

计算机是用补码来进行储存

在计算机系统中,数值一律用补码来表示和储存。原因在于,使用补码,可以将符号位和数值域统一进行处理。

这里我写一段代码,进行调试,来演示计算机为什么用补码来表示和储存

int main()
{
    int a = 20;
    int b = -10;
    return 0;
}

int a = 20;

00000000000000000000000000010100 - 20原码

00000000000000000000000000010100 - 20反码

00000000000000000000000000010100 - 20补码

在调试的内存窗口中,地址输入:&a,再把列改为4,可以看见 14 00 00 00 ,但是为什么是这样显示的呢?

因为内存显示的是16进制位,那就把20的补码拿来进行计算吧。

4个比特位(bit)就是一个16进制位,在二进制位中4个1就是15,十六进制,又是逢十六进一。

所以就4个比特位就是一个16进制位咯。

这样计算下来就是:00 00 00 14

int b = -10;

10000000000000000000000000001010 - -10原码

11111111111111111111111111110101 - -10反码

11111111111111111111111111110110 - -10补码

在调试的内存窗口中,地址输入:&b。也可以看见-10的十六进制位

十六进制的10 11 12 13 14 15 等于 a b c d e f

4个1就是二进制的15,所以就等于一个f

用-10的补码来计算就是:FF FF FF F6

这样就可以说明在计算机中是使用补码来进行表示和储存的了。


大小端字节序储存

在上边清楚了,关于计算机是拿补码来储存和计算的。

关于上边的内存窗口中显示的数据为什么是倒着放。

这里就可以讲讲大小端字节序储存了。

大端字节序储存:

就是把一个数据的低位字节的数据,存放在高地址处,

把高位字节的数据,存放在低地址处。

小端字节序储存:

就是把一个数据的低位字节的数据,存放在低地址处

把高位字节的数据,存放在高地址处。

什么是高位字节的数据和低位字节的数据呢?

比如:

一个123,其中的1是百位,2是十位,3是个位。这里的1就是高位字节的数据,3就是低位字节的数据。

关于大端字节序储存小端字节序储存,在内存中又是怎么显示的呢?

这是一段代码,里面的变量a存储的是十六进制的数据。其中的11是高位字节序,44是低位字节序。

int main()
{
    int a = 0x11223344;
    return 0;
}

如果内存是左边是低地址,右边是高地址。11 在左边低地址处,44在右边高地址处。那么11 22 33 44,就是大端字节序储存。

如果11 是在右边高地址处,44是在左边低地址处,那么44 33 22 11,这样存就是小端字节序储存

咱们再来看一下,调试中的内存窗口是怎么显示的。

这里我用的是Visual Studio 2019来进行调试,当调试创建好了a的变量时,再到内存窗口的地址中&a,右边列里的自动改为4,就可以看见a地址里是如何储存的。

0x004FFCD8是a的地址。

可以看到这和我们变量a存的数据相反,11是高位字节序,但是在右边。44是低位字节序,现在在左边。

就可以知道原来这个数据是用小端字节序进行储存的。

刚才咱们明白了大小端是怎么存储的

那下面就来写一个判断大小端的代码吧。

判断大小端

这里先创建一个int类型的a变量,给个1的值。为什么是1呢?

在十六进制下的1是0x00000001, 00 是高位字节序,01 是低位字节序。

在大端存储下就是 00 00 00 01 ,左边是低地址,右边是高地址。

在小端存储下就是 01 00 00 00

如果是大端字节,前面就是一个字节00 ,小端字节就是01,那么这样就好分辨了。

因为a是int 4个字节类型的,所以需要强制转换为char 的1个字节类型给它的第一个字节,来判断。

就可以写一个char*来强制转换,用一个char* p来存储。然后if来判断是否为1就行了。

int main()
{
    int a = 1;
    char* p = (char*)&a;
    if (*p == 1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}

可以看见是最后输出的是小端

当然这个也可以封装成函数类型

这边如果是小端,就让他返回1,是大端就返回0。

这样的话就可以这样写

创建check_sys函数,在里边创建int a = 1;然后直接return *(char*)&a,如果*(char*)&a得到的是1,那么就直接返回1,如果是0就直接返回0。

int check_sys()
{
    int a = 1;
    return *(char*)&a;
}

int main()
{
    if (check_sys() == 1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}

最后谢谢观看,如果那里写得不对的地方,欢迎提出,探讨。白白

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值