数据在计算机中的存储

目录

原码,反码和补码

大小端字节序存储

有符号和无符号

测试案例

eg.1

eg.2

eg.3


原码,反码和补码

在计算机中数据是以二进制进行存储的,并以其二进制的补码进行存储

二进制分为原码,反码,补码,且二进制的最高位称为符号位

原码就是将这个数字转化成二进制的形式

对于正数和零,其原码,反码,补码相同,而对于负数,其原码中符号位不变,其他位按位取反得到反码,反码加1得到补码

以10 和 -10 为例

原码:

10  00000000000000000000000000001010

-10 10000000000000000000000000001010

反码:

10  00000000000000000000000000001010

-10 111111111111111111111111111111110101

补码:

10   00000000000000000000000000001010

-10  111111111111111111111111111111110110

在计算机中之所以使用补码对数据进行存储,主要是因为 补码中 0的表示 是唯一的:

原码 :10000000000000000000000000000000

          00000000000000000000000000000000

表示一个是 -0 一个是 0,而 -0 和 0 都是零,则导致 0 的表示方法不唯一,在计算中其表示的数据范围将减少

并且cpu中只有加法器没有减法器,使用补码可以简化硬件,例如

1 - 1 可以看成 1 + (-1)

利用原码:

00000000000000000000000000000001

10000000000000000000000000000001

结果:

10000000000000000000000000000010

而10000000000000000000000000000010 表示的是-2,与我们想要的结果不符

利用反码:

00000000000000000000000000000001

111111111111111111111111111111111110

结果:

1111111111111111111111111111111111111 

将其符号位不变并将其他位按位取反得到原码

10000000000000000000000000000000  表示的是-0,虽然得到了0,但因为第一个原则,所以不适用

利用补码:

00000000000000000000000000000001

1111111111111111111111111111111111111

结果

100000000000000000000000000000000

因为在计算机中只能存储32位bit的数据,而其是33位所以会截断,其在计算机中的结果变为

00000000000000000000000000000000,也就是0,说明其可以得到零,且零的表示是唯一的,故而采用补码来进行数据的存储

大小端字节序存储

在内存中,数据的存储又分为 大端字节序存储 和 小端字节序存储,其方式是与硬件结构相关,而与编译器无关,其中大端字节序存储就是将高的二进制序列存到高位,小的二进制位存到低位,而小端字节序存储与其恰恰相反。

比如我们定义一个整型:

int a = 0x11223344;

其是一个用十六进制写出的数字最高位为 11 其次为 22 ,33 最低位 为44

若其在内存中的存储形式为 11 22 33 44 则说明是大端字节序存储

若其在内存中的存储形式为 44 33 22 11 则说明是小端字节序存储

那么我们能否编写一段代码,来检测自己的设备到底是大端字节序存储还是小端字节序存储呢?

答案当然是肯定的

比如以下代码:

#include <stdio.h>

int main()
{
    int a = 0x11223344;
    int b = *(char*)&a;    
    if(b == 0x44)
    {
        printf("小端字节序存储\n");
    }
    else
    {
        printf("大端字节序存储\n");
    }
    return 0;
}

我们对a取地址可以得到a的地址,若此时解引用则会的到a原来的值,因为int类型的指针在解引用时会将其接下来的四个字节当成一个数据,所以此处我们利用char*进行强制类型转换,而char类型的指针,在解引用时只会将当前的这一个字节当成一个数据进行处理,这样我们就得到了a在内存中第一个字节所存储的元素,若我的设备是小端字节序存储,那么我获取到的值就是0x44,否则就应该是0x11,所以可以利用数据的比较来获取我们当前设备的存储形式。

为了便于使用,我们可以将其封装成一个函数:

#include<stdio.h>
//1,表示小端字节序存储, 0表示大端字节序存储
int check_sys()
{
    int a = 1;
    return *(char*)&a;
}

若其为小端字节序存储,则应当取到1,否则应当取到0,直接将其取到的数据返回即可

有符号和无符号

在C语言中,基础数据类型可大致分为整型和浮点型(实型)

整型家族:

        char                         unsigned char                    signed char

        short [int]                 unsigned short [int]             signed short [int]

        int                            unsigned int                        signed int

        long [int]                  unsigned long [int]              signed long [int]

        long long [int]          unsigned long long [int]       signed long long [int]

因为在计算机中,字符型存储的是字符的ASCII码值,所以也可以分为整型

其中又分为有符号和无符号两类,有符号则最高位是符号位。

用unsigned 标识出来的是无符号类型,用signed 标识出来的是有符号类型,在不写其是否有符号时,默认时有符号的,对于无符号数,其有对应的格式控制字符

        %u        ----         无符号整型

        %lu       ----         无符号长整型

        %llu      ----         无符号长长整型

其中无论是有符号数,还是无符号数,在内存中的存储方式都是相同的,只是解析的时候有所差异,对于有符号数,最高位被解释位符号位,而对于无符号数,最高位被解释位数字。

测试案例

eg.1

#include<stdio.h>

int main()
{
    char a = -1;
    signed char b = -1;
    unsigned char c = -1;
    
    printf("a=%d,b=%d,c=%d",a,b,c);

    return 0;
}

其中a是没有注明是否有符号的,则默认是有符号的,所以a在内存里的二进制序列为11111111,

b注明是有符号的,所以b在内存里的二进制序列为11111111

c注明是无符号的,并且-1的2进制序列(补码)为11111111,

而其输出控制字符为均为%d,而他们都是char类型,所以要进行整型提升

提升时,就会按照其符号位进行提升,即为最高位,对于无符号数据类型,则以0进行提升

则 a : 11111111111111111111111111111111

     b: 11111111111111111111111111111111

     c:  00000000000000000000000011111111

所以a为-1,b为-1,c为2^8-1也就是255

运行结果:

 证明我们的推理是正确的

eg.2

#include<stdio.h>
int main()
{
    char a = -128;
    printf("%u\n",a);
    return 0;
}

对于此题,a未注明是否有符号,所以当有符号处理,-128的补码为10000000

所以a中存储的就应当是10000000,但需要注意的是格式控制字符 %u,根据上面的介绍,我们已经得知,%u 是无符号整型的,所以需要对a进行整型提升,将a变为

11111111111111111111111110000000

也就是2^32 - 2 ^ 7 ,借助计算器我们可以得到其结果位4294967168

运行结果:

eg.3

#include<stdio.h>

int main()
{
    char a = 128;
    printf("%u\n",a);
    return 0;
}

此题与上一题相同,也需要对a进行整型提升,而a位字符型,只能存储1个字节,其范围为

-128~127,此时存的数据为128,而128对应的二进制序列为00000000000000000000000010000000,存储时整型截断,所以a在内存中的二进制序列为10000000,也就是 -127,所以此题与上一道题的答案相同,也就是4294967168

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值