栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言中整形、浮点型数据在内存中的存储和使用

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言中整形、浮点型数据在内存中的存储和使用

我们在存储数据时首先是声明数据类型,如int,char,long等,声明类型的是向内存申请对应类型大小的一块内存空间,以对数据进行存储。

以下为不同数据类型的空间大小

  • char 1个字节
  • short 2个字节
  • int 4个字节
  • long long 8个字节
  • float 4个字节
  • double 8个字节

    而一个字节为八个bit位,对应八个二进制位,因此解释每个数据类型对应的数据范围。

    整数类型又有有符号数和无符号数的类型,简单来说,有符号数和无符号数的数据长度范围是一样的,区别在于无符号类型不区分二进制的数据正负,统一转化为正数。

    如char类型,unsigned char的范围是-128~127 ,char的范围是0-255。区间长度都是256


    首先说整形的存储

    整数的转码有三种:原码,反码,补码。

    先贴一下鹏哥对这里的解释

    他后面又解释到使用时的数据提升等等

    但是在我的思考里,这种说法有两点不能对存储的现象进行很好的解释

      对于超出范围的负数,数据的二进制位数如果超出类型的范围,符号位的储存和数据冲突,怎么规定符号位?解释数据在范围里循环时比较生硬,比如char类型里(bin)1000 0000如果按照符号位的说法解释为什么是-128是只能说是规定。

    因此在思考并验证多次之后,写出我对C语言里数据的存储和不同类型使用方式的思考。(我并没有深度学习原理,这里只是我的思考,并不一定正确,如果之后的学习里能够探得真相,我会有解释。)

    首先仍然是三码

    原码:根据原来的数据直接转化为二进制得到反码:将原码按位取反(此时没有符号位)补码:反码加1

    对于正数,存储到内存中三码相同,直接得到原码的二进制序列。

    对于负数,并不会储存符号位,在有负号的时候,编译器会将数据去掉符号直接进行原码,反码,和补码的转换,得到二进制序列。

    之后,根据申请数据类型的空间大小,储存二进制位数。从低位向高位存储(由于windows的小端字节序的存储方式)。

    使用时,根据数据类型,再进行相应的转换

    如果是无符号数,直接进行数据的翻译如果是有符号数,将现有的最高位看成符号位,如果是0,则表示为正数,直接翻译;如果是1,则表示位负数,将数据按照补码转化为原码,再打印加负号的数值。如果有类型提升,高位补符号位

     这种说法,既解释了为什么超出数据范围的大数为什么常常显示负数,也能很好的解释char类型里(bin)1000 0000为什么是-128

     举例:
    int main()
    {
    	char a = -1;
        unsigned char c = -1;
        printf("%d %d",a,c);
        //结果是-1 255
    	return 0;
    }

    首先-1有负号,则进行原反补的转化0000 0001 -> 1111 1110 -> 1111 1111 分别存入a,c的内存

    然后使用时a 首位是1 打印负号,取反为0000 0000-> 0000 0001 打印为1,所以为-1

                      c 由于c是无符号数,直接翻译1111 1111 为255

    补充,这里%d使用是整形,要对数据进行提升,不过一个符号位是0,一个没有符号位所以省略

    int main()
    {
    	char n = -128; 
    	printf("%u ", n);
    	printf("%d", n);
        //结果是4294967168  -128
    	return 0;
    }

    首先仍然128进行原反补转换,1000 0000 -> 0111 1111 -> 1000 0000

    使用时为整形,数据提升1111 1111 1111 1111 1111 1111 1000 0000

    第一行为无符号数直接转化为4294967168

    第二行为有符号数转化 为0000 0000 0000 0000 0000 0000 0111 1111

                                     加1  0000 0000 0000 0000 0000 0000 1000 0000     打印为-128

    int main()
    {
        char arr[1000];
        for (int i = 0; i < 1000; i++)
        {
            arr[i] = -1 - i;
        }
        printf("%d", strlen(arr));//结果为255
        return 0;
    }

    这里有一点,数据持续自减,到下限之后会循环

    这里从-1开始减到-128 补码为1000 0000

    再减1为 0111 1111 首位是0,则为正数,转换为127

    再继续减小,到0时存在char类型的数组里,由ASCII表翻译为‘’

    strlen计算长度为255,正好为char的数据区间


    思路捋下来,也没明显的解决什么其实,但是这样对个人来说更方便理解

    最让我感到惊奇的是数据加减处理时用到的补码,真是个神奇的东西,对于能把正数负数统一加法处理,这就是理科的魅力吧。


    浮点数的储存

    首先需要注意一点,浮点数和整数的内存使用视角不一样

    int main()
    {
        int n = 9;
        float* pn = (float*)&n;
        printf("%dn", n);//结果是9
        printf("%fn", *pn);//结果是0.000000
        *pn = 9.0; 
        printf("%dn", n);//结果是1091567616
        printf("%dn", *pn);//结果是0
        printf("%fn", *pn);//结果是9.000000
        //以浮点数的方式拿数据和存数据的方式和整形不一样
        return 0;
    }

    首先申请空间时的命名n 为整形,其使用内存中数据的角度时整形的存放

    当我们取指针pn将其强制转化为浮点型的指针。*pn得到使用浮点型的视角

    这里要和数据类型转换 float  m = (float)n;区分开,这是数据层面的转换,而不是内存视角

    存储:

    首先转化为二进制

            小数点后面的位数的转换是2的(-n)次方

            比如 5.5 为 2^2 + 2^0 + 2^(-1)   则其二进制表示为101.1

    其次,根据IEEE规定,任意一个二进制浮点数可以表示称下面的形式:

    如5.5,即101.1,首先为整数 s = 0;然后转化为1.011*2^2,则E为2;M为1.011

     

    M总归可以进行移位到1.xxx所以可以把小数点前的1省略掉,直接存储后面

    由于E可能为负数,因此为了确保E为正数,需要将E加上一个中间数

    这是以浮点型视角进行内存的存储

    我们回头继续看

    int main()
    {
        int n = 9;
        float* pn = (float*)&n;
        printf("%dn", n);//结果是9
        printf("%fn", *pn);//结果是0.000000
        *pn = 9.0; 
        printf("%dn", n);//结果是1091567616
        printf("%dn", *pn);//结果是0
        printf("%fn", *pn);//结果是9.000000
        //以浮点数的方式拿数据和存数据的方式和整形不一样
        return 0;
    }

     当存入9的时候,整形的视角存入补码为0000 0000 0000 0000 0000 0000 0000 1001

    *pn 时为-1^0 * 2^(-127)*(1.000 0000 0000 0000 0000 1001) = 0.000000

    *pn = 9.0时,存入的为-1^0 * 2^(127+3) * 1.001

    内存中为 0100 0001 0001 0000 0000 0000 0000 0000

     因此为这个数


    对于浮点数精度的解释,我现在并没有想的非常清楚,很明显它同时受e和m的限制,但是之后的使用中,小数点前后位数的权重,还要继续学习。

  • 转载请注明:文章转载自 www.mshxw.com
    本文地址:https://www.mshxw.com/it/717879.html
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号