当前位置 博文首页 > ifwecande的博客:深入了解C语言中数据的存储

    ifwecande的博客:深入了解C语言中数据的存储

    作者:[db:作者] 时间:2021-08-15 13:34

    C语言是贴着计算机运行的一种语言
    相对于其他语言我们更需要了解C语言中不同的数据都是怎么存储的。

    深度剖析的话 可将其分为四个方向
    1. 数据类型介绍
    2. 整形在内存中的存储:原码、反码、补码
    3. 大小端字节序介绍及判断
    4. 浮点型在内存中的存储解析

    我们从第一个开始来逐个进行解读

    1. 数据类型介绍

    基本数据类型介绍
    char //字符数据类型
    short //短整型
    int //整形
    long //长整型
    long long //更长的整形
    float //单精度浮点数
    double //双精度浮点数

    对数据类型的进行一个基本归类 我们可以将其分为以下五组
    整形家族:
    浮点数家族:
    构造类型:
    指针类型
    空类型:
    void 表示空类型(无类型)
    通常应用于函数的返回类型、函数的参数、指针类型。

    2. 整形在内存中的存储

    我们知道变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。
    我们要知道这些空间计算即是如何开辟的?计算机又是如何将数据存储起来的?
    我么先来了解这几个概念
    计算机中的有符号数有三种表示方法,即原码、反码和补码。
    三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位
    三种表示方法各不相同。
    原码
    直接将二进制按照正负数的形式翻译成二进制就可以。
    反码
    将原码的符号位不变,其他位依次按位取反就可以得到了。
    补码 反码加1就能得到原码的补码
    正数的原、反、补码都相同。

    对于整形来说:数据存放内存中其实存放的是补码。
    为什么呢?
    在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理; 同 时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需 要额外的硬件电路。

    3.大小端介绍

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

    一道判断大小端的题目

    #include <stdio.h>
    int check_sys()
    {
    	int i = 1;
    	return (*(char *)&i);
    }
    int main()
    {
    	int ret = check_sys();
    	if (ret == 1)
    	{
    		printf("小端\n");
    	}
    	else
    	{
    		printf("大端\n");
    	}
    	return 0;
    }
    //代码2 
    int check_sys()
    {
    	union
    	{
    		int i;
    		char c;
    	}un;
    	un.i = 1;
    	return un.c;
    }
    

    这道判断大小端的题目巧妙地运用了C语言的隐式类型转换是字节的截断和提升 从计算即大小端存储差异入手 从而巧妙地进行解答

    4.浮点型在内存中的存储

    我们曾经学习过的浮点数包括: float、double、long double 类型。
    但是浮点数与整形在计算机中的存储却大不相同
    我们来看一段代码

    int main()
     {
     int n = 9; 
     float *pFloat = (float *)&n; 
     printf("n的值为:%d\n",n);    
     printf("*pFloat的值为:%f\n",*pFloat);
     *pFloat = 9.0;   
     printf("num的值为:%d\n",n); 
     printf("*pFloat的值为:%f\n",*pFloat);  
    return 0; 
    } 
    

    运行结果如图
    在这里插入图片描述
    解读:
    根据国际标准IEEE 754,任意一个二进制浮点数V可以表示成下面的形式: (-1)^S * M * 2^E (-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。 M表示有效数字,大于等于1,小于2。 2^E表示指数位。
    举例来说: 十进制的5.0,写成二进制是 101.0 ,相当于 1.01×2^2 。 那么,按照上面V的格式,可以得出s=0, M=1.01,E=2。 十进制的-5.0,写成二进制是-101.0 ,相当于-1.01×2^2 。那么,s=1,M=1.01,E=2。

    因此对于计算机来说也得按照这种方法进行存储
    对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
    对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。

    特别规定.
    1≤M<2
    M可以写成 1.xxxxxx 的形 式,其中xxxxxx表示小数部分。
    IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。
    指数E
    首先,E为一个无符号整数 所以IEEE 754规定,存入内存时E的真 实值必须再加上一个中间数,对于8位的E,这个中间数是127

    我们经过简单了解现在再对上面的题进行一个合理的解释
    对于前两个printf 首先
    int n=9;
    然后我们将n的地址取出来存入了一个指针变量中
    我们知道 地址在内存中一般是占四个字节的 int的变量在内存中也是占四个字节进行存储的
    注意
    float*是一个浮点型的指针
    int位整型变量
    我们将整形取地址然后强转成一个float的地址进行存储 显然当我们进行读取时候 会出现错误
    n=9的二进制 00000000 00000000 00000000 00001001
    当转成float时 因为 float数据分三部分进行存储
    对于 00000000 00000000 00000000 00001001 将该数据看作浮点数的话 是一个很小的数据 (-1)^0 * 10 ^0 *1.0000000…… 此处省略
    因此打印出来的结果就是一个0.000000 (float数据打印时小数点后跟默认六位)

    然后对后面两个printf进行分析
    我们在打印前首先对pfloat的值进行了一个改变 --9.0
    因此 n的地址的值就发生了改变 同样的
    pfloat的值也发生了改变
    *pfloat打印出来的值是9.000000 很容易理解
    n的值打印出来是一个奇怪的数字
    9 的二进制表示 00000000 00000000 00000000 00001001
    按照上述规则
    9.0内存中存储 0 10000010 001 0000 00000000 00000000
    我们将其转化为十进制发现正好是
    1091567616

    cs
    下一篇:没有了