• C语言内功修炼【整型在内存中的存储】


     

    目录

    ✂️ 一类型的基本归类

    ☝️ 1.整型家族

    ✋ 2.浮点型家族

    ✋ 3.构造类型 - 自定义类型

    ✌️ 4.指针类型

    ✊ 5.空类型

    ✒️ 二、整型在内存中的存储

    ✏️ 三、大小端介绍

    ⚽ 四、百度2015年系统工程师笔试题

     ⚾️五、练习题

    1.⛳

    2.⛳⛳

    3.⛳⛳⛳

    4.⛳⛳⛳⛳

    5.⛳⛳⛳⛳⛳

    6.⛳⛳⛳⛳⛳⛳

    7.⛳⛳⛳⛳⛳⛳⛳


    ✂️ 一类型的基本归类

    ☝️ 1.整型家族

    1. char
    2. unsigned char
    3. signed char
    4. short
    5. unsigned short[int]
    6. signed short[int]
    7. int
    8. unsigned int
    9. signed int
    10. long
    11. unsigned long[int]
    12. signed long[int]

    ⚠️

    注意:unsigned char 是无符号的char;signed char 是有符号的char

    若以后创建的变量只会存正数,就可以使用 unsigned ,对于用 shortint 还是 long long 要考虑数值的大小

    ✋ 2.浮点型家族

    1. float
    2. double

    ✋ 3.构造类型 - 自定义类型

    数组

    struct 结构体类型

    enum 枚举

    union 联合体

    ✌️ 4.指针类型

    1. int* pi;
    2. char* pc;
    3. float* pf;
    4. void* pv;

    ✊ 5.空类型

    void 表示空类型(无类型)

    通常应用于函数的返回类型、函数的参数、指针类型。

    ✒️ 二、整型在内存中的存储

    数据在内存中是以 二进制 的形式存储

    对于整数来说:

    整数二进制有3中表示形式:原码、反码、补码

    正整数:原码、反码、补码相同

    负整数:原码、反码、补码是要进行计算的

    计算方法:

    按照数据的数值直接写出的就是原码

    原码的符号位不变,其它位按位取反,得到的就是反码

    反码 +1 得到的就是补码

    ⚠️

    注意:整数在内存中存储的是补码。

    例子:

    1. #include<stdio.h>
    2. int main()
    3. {
    4. int a = -10;
    5. //10000000000000000000000000001010 - 原码
    6. //11111111111111111111111111110101 - 反码
    7. //11111111111111111111111111110110 - 补码
    8. return 0;
    9. }

           内存中是以十六进制展示的,而我们写出的是二进制,如果把二进制转化成十六进制,再进行比较就可以看出内存中存的是原码、反码、还是补码。

           二进制的四个位可以换一个十六进制位,前面28个比特位可以换7个F,0110可以换成6,也就是FFFFFFF6,根据前面的图片可以发现在内存中是倒着存的,这也说明了整数在内存中存的是补码。那么为什么会倒着存?以及为什么存的是补码?将在后面进行解释。。

    为什么在内存中存的是补码,而不是原码或反码呢?

           原因:在计算机系统中,数值一履用补码表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码和原码相互相互转换,其运算过程是相同的,不需要额外的硬件电路。

    例子:

    1. #include<stdio.h>
    2. int main()
    3. {
    4. //1 - 1;
    5. //由于CPU只有加法器,所以使用加负1来代替减1
    6. //1 + (-1);
    7. //假设使用原码来计算:
    8. //1的原码: 00000000000000000000000000000001
    9. //-1的原码:10000000000000000000000000000001
    10. //1 + (-1)的结果是:1000000000000000000000000000010
    11. //转化为十进制是-2,发现并不是我们想要的值
    12. return 0;
    13. }

    结论:使用原码计算,无法得到我们预期想得到的值。 

    若使用补码计算:

    1. #include<stdio.h>
    2. int main()
    3. {
    4. //1 - 1;
    5. //由于CPU只有加法器,所以使用加负1来代替减1
    6. //1 + (-1);
    7. //假设使用原码来计算:
    8. //1的补码: 00000000000000000000000000000001
    9. //-1的原码:10000000000000000000000000000001
    10. //-1的反码:11111111111111111111111111111110
    11. //-1的补码:11111111111111111111111111111111
    12. //1的补码: 00000000000000000000000000000001
    13. //-1的补码:11111111111111111111111111111111
    14. //1 + (-1)的结果是:00000000000000000000000000000000
    15. //转化为十进制是0,是我们想要的值
    16. return 0;
    17. }

    结论:使用补码计算,可以得到我们预期想得到的值,所以要使用补码计算。

    ✏️ 三、大小端介绍

    为什么整数里的正数和负数在内存中是倒着存储的?

    解决这个问题要先介绍大端和小端的。那么什么是大端小端?

    什么是大端小端:

    大端(存储)模式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。

    小端(存储)模式:是指数据的高位保存在内存的低地址中,而数据的低位,保存在内存的高地址中。

    为什么会有大端和小端:

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

    例子:

    这里展示用的是16进制,但内存中存的是二进制

    正着存倒着存都可以,但是要怎么存进去的,怎么拿出来。

    后面两种的存储顺序太复杂了,可以这样存,但是使用起来太复杂了。所以也就保留了前面两种较为简单的顺序。

    这四个字节是按照什么样的顺序存在内存中的,我们讨论的是存储在内存中字节的顺序,所以就叫字节序。

    字节序分两种:大端字节序,小端字节序。 

    ⚽ 四、百度2015年系统工程师笔试题

    请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序

    1. #include<stdio.h>
    2. int main()
    3. {
    4. int a = 1;
    5. char* p = (char*)&a;
    6. if (*p == 1)
    7. {
    8. printf("小端\n");
    9. }
    10. else
    11. {
    12. printf("大端\n");
    13. }
    14. return 0;
    15. }

    函数写法:

    1. #include<stdio.h>
    2. int check()
    3. {
    4. int a = 1;
    5. char* p = (char*)&a;
    6. if (*p == 1)
    7. {
    8. return 1;
    9. }
    10. else
    11. {
    12. return 0;
    13. }
    14. }
    15. int main()
    16. {
    17. int ret = check();
    18. if (1 == ret)
    19. {
    20. printf("小端\n");
    21. }
    22. else
    23. {
    24. printf("大端\n");
    25. }
    26. return 0;
    27. }

     函数写法的优化版本:

    1. #include<stdio.h>
    2. int check()
    3. {
    4. int a = 1;
    5. char* p = (char*)&a;
    6. return *p;
    7. }
    8. int main()
    9. {
    10. int ret = check();
    11. if (ret == 1)
    12. {
    13. printf("小端\n");
    14. }
    15. else
    16. {
    17. printf("大端\n");
    18. }
    19. return 0;
    20. }

     ⚾️五、练习题

    1.⛳

    1. #include<stdio.h>
    2. int main()
    3. {
    4. char a = -1;
    5. //-1的原码:10000000000000000000000000000001
    6. //-1的反码:11111111111111111111111111111110
    7. //-1的补码:11111111111111111111111111111111
    8. signed char b = -1;
    9. //b的补码与a相同
    10. unsigned char c = -1;
    11. //c也是与a相同
    12. printf("a = %d,b = %d,c = %d", a, b, c);
    13. return 0;
    14. }

     解析:

    内存中存的是补码
    char 有一个字节,等于 8 个比特位,-1是有 32 个比特位,将 -1 存到 a 中,a 是 char 类型,a 里面只能存 -1 补码的低 8 位。
    11111111

    signed char 是一个有符号的 char ,所以和 a 一样,b 里面只能存 11111111
    unsigned char 是一个无符号的 char ,但它也是个 char ,c 也只能存 11111111
    要通过 %d 打印一个整型,这里会发生整型提升,因为是有符号位,所以高位要补符号位
    11111111111111111111111111111111

    这 32 个 1 是补码, %d 打印的是原码,也就是打印 -1 , a 也就等于 -1 , b 与 a 相同。
    unsigned char 是无符号的 char ,高位补的是 0
    00000000000000000000000011111111
    高位是 0 表示它是整数,整数原反补相同
    转化为十进制打印也就是 255 

    补充:

    char 到底是 signed char 还是 unsigned char ?
    ''C语言标准并没有规定,取决于编译器
    int 是 signed int
    short 是 signed short

    结果:

    a=-1,b=-1,c=255

    2.⛳⛳

    1. #include<stdio.h>
    2. int main()
    3. {
    4. char a = -128;
    5. //-128的原码:1000000000000000000000010000000
    6. //-128的反码:1111111111111111111111101111111
    7. //-128的补码:1000000000000000000000010000000
    8. printf("%u", a);
    9. return 0;
    10. }

    解析:

    a是一个 char 类型,只能存8个比特位。
    10000000

    %u 打印要发生整型提升,因为是有符号的 char,高位补符号位。
    11111111111111111111111110000000
    %u 打印一个无符号整型,无符号表示是整数,原反补相同,此时的补码就是原码,转化为十进制后输出结果

    如果是以 %d 打印,%d 是打印有符号整数,回通过计算得到原码,最后输出 -128

    结果:

    4294967168

    3.⛳⛳⛳

    1. #include<stdio.h>
    2. int main()
    3. {
    4. char a = 128;
    5. //128的原码:1000000000000000000000010000000
    6. //因为是正数。原反补相同
    7. printf("%u", a);
    8. return 0;
    9. }

    解析:

    char 类型只能存8个比特位
    10000000

    因为是有符号的 char%u 打印,整型提升,高位补符号位
    11111111111111111111111110000000
    %u 打印无符号整数,原反补相同,转化为十进制

    补充:
    char 类型变量的取值范围

    结果:

     4294967168

    4.⛳⛳⛳⛳

    1. #include<stdio.h>
    2. int main()
    3. {
    4. int i = -20;
    5. //-20的原码:10000000000000000000000000010100
    6. //-20的反码:11111111111111111111111111101010
    7. //-20的补码:11111111111111111111111111101100
    8. unsigned int j = 10;
    9. printf("%d\n", i + j);
    10. return 0;
    11. }

    解析:

    10是整数,原反补相同
    00000000000000000000000000001010

    i的补码 + j的补码:
    i:11111111111111111111111111101100
    j:00000000000000000000000000001010
    i + j 的补码:11111111111111111111111111110110

    因为以 %d 打印,转化为原码后为
    10000000000000000000000000001010
    转化为十进制输出结果

    结果:

    -10

    5.⛳⛳⛳⛳⛳

    1. #include<stdio.h>
    2. int main()
    3. {
    4. unsigned int i;
    5. for (i = 9; i >= 0; i--)
    6. {
    7. printf("%u\n", i);
    8. }
    9. return 0;
    10. }

    解析:

           i是一个无符号整型,不可能为负数,最小是0,%u 打印一个无符号数,判断条件是大于等于0,i的值一直减小到0就不会继续减小了,也就无法跳出循环。

    结果:

    死循环

    6.⛳⛳⛳⛳⛳⛳

    1. #include<stdio.h>
    2. int main()
    3. {
    4. char a[1000];
    5. int i;
    6. for (i = 0; i < 1000; i++)
    7. {
    8. a[i] = -1 - i;
    9. }
    10. return 0;
    11. }

    解析:

    a[i]的值依次为-1 -2 -3......-127 -128 127 126 125......3 2 1 0 -1 -2 ...... -127 -128 127......

    因为是char类型,能存的最大负数和最大整数依次是
    -128和127

    第3题有做详细介绍

    结果:

    255

    7.⛳⛳⛳⛳⛳⛳⛳

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

    解析:

    unsigned char 是无符号的 char,i 的范围只能是0~255,而判断条件是小于等于255,无法跳出。

    结果:

    死循环

     

  • 相关阅读:
    软件测试进阶(黑白盒测试)
    [量化投资-学习笔记002]Python+TDengine从零开始搭建量化分析平台-MA均线的多种实现方式
    Linux下gz和tar.gz、与Windows天zip压缩解压
    mybatise-plus的id过长问题
    购物车页面的测试用例设计
    SpringCloud——Gateway(使用redis做限流、跨域)
    高级前端手写面试题
    马赛克后挡板是什么?
    Integer超出-128——127范围的数值比较为什么要用equals
    电子协会 C语言 1级 33 、奇偶数判断
  • 原文地址:https://blog.csdn.net/m0_63033419/article/details/124991298