• 数据在内存中的存储(1)——整形


    目录

     

    1、数据类型介绍

            1.1、类型的基本归类

                    整形家族

                    浮点数家族

                    指针类型

                    空类型

                    构造类型

    2、整形在内存中的存储

             2.1、原码、反码、补码

             2.2、大小端介绍

             2.3、有符号与无符号 

             2.4、练习

            例一

            例二

            例三

            例四

            例五 


     

    1、数据类型介绍

    我们先来简单了解一下我们前面所学的基本的内置类型

    数据类型数据名占内存字节数表示范围
    char字符数据类型1-128~127
    short短整型2-32,768~32,767
    int整形4-2,147,483,648~2,147,483,647(-231 ~ 231-1)
    long长整型4或者8-2,147,483,648~2,147,483,647(-231 ~ 231-1)
    long long更长的整形8-9223372036854775808~9223372036854775807
    float单精度浮点数4-3.4x10-38 ~ 3.4x1038
    double双精度浮点数8-1.7x10-308 ~ 1.7x10308

    这么多类型存在的意义在于使用者可以选择自己所需要合适的类型

     

            1.1、类型的基本归类

    根据这些数据类型,我们给他们做一个简单的分类

                    整形家族

    char

    unsigned  char

    signed  char

    short

    unsigned  short

    signed  short

    int

    unsigned  int

    signed  int

    long

    unsigned  long

    signed  int

    这里char为什么放在整形家族里呢?是因为字符在存储的时候,存储的是ASCII码值,是整型,所以放在整型家族里,蓝色为无符号,紫色为有符号后续会讲到,这儿保留悬念

                    浮点数家族

                                                float
                                               double

                    指针类型

       关于指针有疑问的小伙伴可以去看看博主对指针的讲解

    char*  pc
    int*   pi
    float*  float
    void*  pv

                      空类型

    void表示空类型(无类型)
    通常用于函数的参数、函数的返回类型、指针类型

                    构造类型

    数组类型
    结构体类型
    枚举类型
    联合类型

    2、整形在内存中的存储

     一个变量的创建是需要在内存中开辟空间的,而空间的大小是根据不同的类型来决定的。数据在这些空间中以二进制补码的形式存储,而计算机中有符号数有原码,反码,补码三种表示形式,并且还有符号位和数值位,符号位用0表示正数,1表示负数

             2.1、原码、反码、补码

    我们这里用的是整型,而一个整形有4个字节=32bit位,所以二进制表示应为32位,第一位为符号位,1表示负数,0表示正数,中间用0补齐就好,正整数的原码、反码、补码表示如下

    1. int a = 15;
    2. //00000000000000000000000000001111 - 原码
    3. //00000000000000000000000000001111 - 反码
    4. //00000000000000000000000000001111 - 补码

     负整数的原码、反码、补码是需要计算的,计算方法和原码、反码、补码表示如下

    1. int b = -15;
    2. //10000000000000000000000000001111 - 原码
    3. //11111111111111111111111111110000 - 反码(原码的符号位不变,其他位按位取反得到的就是反码)
    4. //11111111111111111111111111110001 - 补码(反码+1就是补码)

      我们还需要明确的是整数在内存中存储的是补码,计算的时候也是使用补码计算的

             2.2、大小端介绍

    在介绍大小端是我们先来看几组现象,有助于我们理解,博主这里使用的编译器为vs2019

    f420b5b84b7444d1bb5fc986b61f27f3.png 但我们查看num的地址我们发现,数据在上面倒着存储,这是正数,我们再来看一下负数 

    e0bda5d7865a4dd2a717e4adf90ae52d.png

    我们发现还是倒着存储的,这是为什么呢?

    这是因为大端和小端这两种存储模式

          大端:是数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。低地址-->>高数据   例如:手机

          小端:是指数据的地位保存在内存的低地址中,数据的高位则保存在内存的高地址中。低地址-->>低数据    例如:电脑
    a8d26cf942614bc28c5d8d38dd6bfec3.png

    这里呢我们想一下,除了通过调试,我们还有没有其他办法来判断大小端呢?

     

    这里我们发现,当a=1时,大小端低位存储的值并不相同,所以我们写出以下代码

    1. //int main()
    2. //{
    3. // int a = 1;
    4. // char* p = (char*)&a;
    5. // if (*p == 1)
    6. // printf("小端\n");
    7. // else
    8. // printf("大端\n");
    9. // return 0;
    10. //}

    那么这个代码又是如实现的呢? 这里我们需要明确一个知识点,其实这个博主在指针是也有所讲到,这里就在浅提一下吧

    ef1c93e92b014bee9755af52181df354.png

    那么也就是所如果是访问的第一个字节是1那么就是小端,如果不是就是大端,如此一来就可以判断了

    为什么会有大小端模式之分呢?

       这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

    大小端存在的意义

    1)在通信协议中,大小端模式是非常重要的。

    2)在实际中,有些CPU用的是大端,有些则是小端,如不加以区别的话,可能会出现读取时和储存时字节顺序不一致的情况,从而造成数据的错误。

    3)网络通信中一般为大端模式,常用计算机CPU为小端模式。


             2.3、有符号与无符号 

         这里注意有符号和无符号只针对整形

    5b0c057e519e4213b359664b7f91aee7.png

    在博主vs编译器上类型前面没有加unsigned都默认为有符号

    我们知道数据在存储时是以二进制存储的,而二进制位的第一位为符号位,我们来看一个简单的演示再理解一下有符号和无符号

    5876946ebea34afd862dd313194c875a.png

    那么有符号与无符号对于我们的表示范围有没有区别呢?答案是显然的,有区别的

    比如我们先来看一下有符号的吧

    e63f18e4997a4afe856023028c8e0b24.png

    再来看一下无符号的,没有符号位,全是数值位

    ed2e383431544081a6b8039b4ee2095c.png

    这里呢我们再拓展一下,当二进制位不断加一时,我们会发现到了极限时,又会回到最初位,这里我们借用大牛的图来理解一下

    有符号的 

    2ef79d2e18604937b9c298d1b63daef6.png

    无符号的

    2c6a3024ed8e469aaa0f57f48856bdbf.png

             2.4、练习

    例一

    1d3354ed5e3846718a651de32e4d9804.png

    下面是代码解释和最终结果 

    1. //#include <stdio.h>
    2. //int main()
    3. //{
    4. // char a = -1;
    5. // //10000000000000000000000000000001 原码
    6. // //11111111111111111111111111111110 反码
    7. // //11111111111111111111111111111111-截断,因为char只占一个字节
    8. // //11111111 -a
    9. // //11111111111111111111111111111111 整形提升
    10. // //11111111111111111111111111111110 反码
    11. // //10000000000000000000000000000001--> -1
    12. //
    13. // signed char b = -1;
    14. // //11111111111111111111111111111111 反码
    15. // //11111111 -b
    16. // //11111111111111111111111111111111 整形提升
    17. // //11111111111111111111111111111110 反码
    18. // //10000000000000000000000000000001--> -1
    19. // unsigned char c = -1;
    20. // //11111111 -c //无符号,前面补0
    21. // //00000000000000000000000011111111--.255
    22. // //
    23. // printf("a=%d,b=%d,c=%d", a, b, c);
    24. // //%d - 十进制的形式打印有符号整型整数
    25. // //整型提升
    26. //
    27. // return 0;
    28. //}

    关于整形提升不懂的宝子,可以看博主在操作符(2)里的讲解 

     例二

    754aee7bd5b0402ba8a5b10dbac31166.png

    5ff264536de449e48e908479fba63ba6.png

     代码解释与运行结果如下

    1. //#include <stdio.h>
    2. //int main()
    3. //{
    4. // char a = -128;
    5. // //-128
    6. // //10000000000000000000000010000000
    7. // //11111111111111111111111101111111
    8. // //11111111111111111111111110000000
    9. // //-128的补码
    10. // //10000000 有符号,补首位
    11. // //11111111111111111111111110000000
    12. // //由于我们打印的是无符号,所以上面就为我们要的原码
    13. // printf("%u\n", a);
    14. // %u打印无符号的十进制数
    15. // return 0;
    16. //}

    例三

    d7ecedccadd2445bac23e7617a58a68a.png

    解释如下

    1. //int main()
    2. //{
    3. // int i = -20;
    4. // //10000000000000000000000000010100
    5. // //11111111111111111111111111101011
    6. // //11111111111111111111111111101100
    7. // //
    8. // unsigned int j = 10;
    9. // //00000000000000000000000000001010 -->10
    10. // //11111111111111111111111111101100 -->-20
    11. // //11111111111111111111111111110110
    12. // //11111111111111111111111111110101
    13. // //10000000000000000000000000001010 -10
    14. // //
    15. // //11111111111111111111111111110110
    16. // //10000000000000000000000000001001
    17. // //10000000000000000000000000001010
    18. // printf("%d\n", i + j);
    19. // return 0;
    20. //}

     例四

    206859c65e42440da4e7b07f14ded083.png

     这里呢由于我们 i 是unsigned int,所 i 是恒大于0的,所以这个函数为死循环

    例五 

    1. //unsigned char i = 0;//0~255
    2. //
    3. //int main()
    4. //{
    5. // for (i = 0; i <= 255; i++)
    6. // {
    7. // printf("hello world\n");
    8. // }
    9. // return 0;
    10. //}

    这里同理,无符号char取值范围为0~255,所以此题也是一个死循环

    关于浮点数,博主会在下一篇进行介绍。

    制作不易,记得一件三连哦!!!

     

      

     

     

  • 相关阅读:
    以数字技术赋能产业金融生态能力建设,破解银行的场景焦虑
    字节为什么要去肥增瘦?
    iterm2 配置自动登录跳板机,无需输入密码和google验证码
    C语言实现将矩阵上下翻转(正反解算结果融合时用到)
    家政服务小程序,提高企业在市场中的竞争力
    黑马Java热门面试题SSM(六)
    torch.gather() 用法解读
    权限系统 RGCA 四步架构法
    汽车行业调研:特种车市场发展趋势及现状分析
    HANA VIEW 用 ABAP 创建CDS VIEW,在生成ODATA
  • 原文地址:https://blog.csdn.net/m0_71731682/article/details/130909934