深入理解计算机系统-之-数值存储(六)--以不同的方式窥视内存

简介:

浮点数写,整数读


好了知道了浮点数的存储方式,那么我们的问题来了,如果我们定义了一个浮点数,那么如果以整数的格式去读取它,会发生什么奇妙的现象

代码示例


我们对上一篇文章中修改main函数为如下形式
我们定义了变量float f = 9.0f, 然后用一个整形指针去读它,由于32位机器上int和float类型的大小是一致的,不会存储访问越界(即使是64位机器,int也不一定为不是32位,因为这个不仅跟机器字长相关,还跟编译器的处理方式相关)

#include <stdio.h>
#include <stdlib.h>


int print_bit(void *addr, int size)
{

    unsigned char *ptr = (unsigned char *)addr;
    int print_bytes = 0;

    if(ptr == NULL)
    {
        return -1; 
    }

    for(print_bytes = 0;
        print_bytes < size;
        print_bytes++, ptr++)
    {
#ifdef DEBUG
        printf("byte %d, data = %02x -=>", print_bytes, *ptr); 
#endif
        for(int print_bits = 7;
        print_bits >= 0;
        print_bits--)
        {
            printf("%d", ((*ptr >> print_bits) & 1));
        }
#ifdef DEBUG
        printf("\n");
#endif

    }
    printf("\n"); 

    return print_bytes;
}

int print_byte(void *addr, int size)
{
    unsigned char *paddr = (unsigned char *)addr;
    int print_bytes = 0;

    if(paddr == NULL)
    {
        return -1; 
    }

    while(print_bytes < size)
    {
        printf("%02x", *paddr); 
        paddr++; 
        print_bytes++; 
    }
    printf("\n"); 
    return print_bytes; 
}


int main(void)
{

    printf("%d == %d\n", sizeof(float), sizeof(int));

    float f = 9.0f; //对于一块内存,按浮点型初始化
    int * pInt = (int *)(&f);
    print_byte((void *)&f, sizeof(f));
    print_bit((void *)&f, sizeof(f));

    printf("the float : %f, %f\n",      f, *pInt); //以浮点视角看
    printf("the int   : %d, %d, %d\n",  f, (int)f, *pInt); //以整型视角看


    *pInt = 9;
    print_byte((void *)&f, sizeof(f));
    print_bit((void *)&f, sizeof(f));
    printf("the float : %f, %f\n",      f, *pInt); //以浮点视角看
    printf("the int   : %d, %d, %d\n",  f, (int)f, *pInt); //以整型视角看

    return EXIT_SUCCESS;
}

这里写图片描述

float 9.0表示出来 =1001×2 0 =1.001×2 3  
阶码=3 +127 =130 =10000010B

符号位 阶码 尾数
0 10000010 00100000000000000000000

存储起来就是0x41100000H

浮点数读


第一种读取方式:直接对这个浮点数按照整数方法读取


这个不需要多说什么,存储格式与读取格式一致

第二种读取方式:用pInt型指针按照浮点数格式读取


首先,将0x00000009拆分,得到第一位符号位s=0,后面8位的指数E=00000000,最后23位的有效数字M=000 0000 0000 0000 0000 1001。
由于指数E全为0,所以符合上一节的第二种情况。因此,浮点数V就写成:
V=(-1)^0×0.00000000000000000001001×2^(-126)=1.001×2^(-146)
显然,V是一个很小的接近于0的正数,所以用十进制小数表示就是0.000000。

整数读


第一种方式,直接printf以”%d”输出浮点数f


这种方式下,出现了一个奇妙的问题,我们的浮点数9.0f用%d输出后,变成了0.0。
这是为什么呢。因为在C语言中浮点数默认为双精度(double),除非指定F,但是printf打印时对于单精度浮点数,仍然要转换成双精度浮点数然后打印,因此

printf("%d", f) <-==->printf("%d", 9.0f);
  • 1
  • 1

会进行如下处理

单精度浮点数:9.0F = 0 | 10000010| 00100000000000000000000

  • 求出它的单精度内存表示,
  • 转换为双精度,有效位不足补0,
  • 输出低32位所表示的十进制数
    总的来说,在打印一个浮点数时,一.浮点数转换成双精度 二. 打印低32位.

因此打印的结果始终为0

第二种方式,强制转换后去读取


将浮点数(单双精度)转换为整数时,将舍弃浮点数的小数部分, 只保留整数部分。将整型值赋给浮点型变量,数值不变,只将形式改为浮点形式, 即小数点后带若干个0。

注意:赋值时的类型转换实际上是强制的。

因此显示的结果是9

第三种读取方式:用一个int型的指针去读取


这个也比较好理解,由于我们用了一个int行的指针去读取
那么编译器处理时会认为这个是一个int型的变量
回到前面float 9.0表示出来是

符号位 阶码 尾数
0 10000110 0110010001000000000

小端模式的存储结构为00001041,编译器出来以后会·按字节进行整合,

存储的int值其实是0x41100000H = 1091567616

第二次读写


接着我们用整形指针向f中写入了数据 *pInt = 9; 虽然我们看起来好像没什么变化,但是其实写入的数据已经发生了很大变化,因为前面的两篇博文我们已经看到,整数和浮点数的存储格式是有很大区别的。
这个操作其实是将一个单精度浮点数标识的9.0f的存储格式,强制变成了整数9的存储格式。
因此进行浮点数读全为0(阶码为0)
而我们用pInt去按照整数读取的时候,由于存储格式本来就是整数的存储格式,因此读取出来是9

整数写,浮点数读

跟上一个例子相反,我们定一个int型变量,然后用float型的指针进行读取

int main(void)
{
    printf("%d == %d\n", sizeof(float), sizeof(int));


    int num = 9;                                /* num是整型变量,设为9 */
    float* pFloat = (float *)&num;              /* pFloat表示num的内存地址,但是设为浮点数 */

    print_byte((void *)&num, sizeof(num));
    print_bit((void *)&num, sizeof(num));

    printf("the float : %f, %f\n",       num, *pFloat); //以浮点视角看
    printf("the int   : %d, %d\n",  (int)num, *pFloat); //以整型视角看


    *pFloat = 9.0f;                                /* 将num的值改为浮点数 */
    print_byte((void *)&num, sizeof(num));
    print_bit((void *)&num, sizeof(num));

    printf("the float : %f, %f\n",       num, *pFloat); //以浮点视角看
    printf("the int   : %d, %d\n",  (int)num, *pFloat); //以整型视角看


    return EXIT_SUCCESS;
}

这里写图片描述

同样我们这个代码,用上面的分析就很简单了。也不过是将一个浮点数的存储格式,强制变成了整数的存储格式而已


转载:http://blog.csdn.net/gatieme/article/details/50709093

目录
相关文章
|
1月前
|
存储 JSON 监控
Higress Controller**不是将配置信息推送到Istio的内存存储里面的**。
【2月更文挑战第30天】Higress Controller**不是将配置信息推送到Istio的内存存储里面的**。
14 1
|
6天前
|
存储 NoSQL Oracle
Oracle 12c的内存列存储:数据的“闪电侠”
【4月更文挑战第19天】Oracle 12c的内存列存储以超高速度革新数据处理,结合列存储与内存技术,实现快速查询与压缩。它支持向量化查询和并行处理,提升效率,但需合理配置以平衡系统资源。作为数据管理员,应善用此功能,适应业务需求和技术发展。
|
16天前
|
存储 C语言
数据在内存中的存储2
数据在内存中的存储2
|
16天前
|
存储 编译器
数据在内存中的存储1
数据在内存中的存储
|
27天前
|
存储 编译器 程序员
【C语言】整形数据和浮点型数据在内存中的存储
【C语言】整形数据和浮点型数据在内存中的存储
16 0
|
1月前
|
存储 Windows 容器
浮点数在内存中的存储
浮点数在内存中的存储
18 2
|
1月前
|
存储 小程序 C语言
【深度剖析数据在内存中的存储】C语言
【深度剖析数据在内存中的存储】C语言
|
1月前
|
存储 小程序 C语言
【C语言进阶】深度剖析数据在内存中的存储
【C语言进阶】深度剖析数据在内存中的存储
|
1月前
|
存储 小程序 编译器
C语言从入门到实战——数据在内存中的存储方式
数据在内存中的存储方式是以二进制形式存储的。计算机中的内存由一系列存储单元组成,每个存储单元都有一个唯一的地址,用于标识它在内存中的位置。计算机可以通过这些地址来定位并访问内存中的数据。 数据在内存中的存储方式取决于数据的类型。数值类型的数据(例如整数、浮点数等)以二进制形式存储,并根据类型的不同分配不同的存储空间。字符串和字符数据由ASCII码存储在内存中。数据结构(例如数组、结构体、链表等)的存储方式也取决于其类型和组织结构。 总之,数据在内存中以二进制形式存储,并根据其类型和组织方式分配不同的存储空间。
43 0
|
1月前
|
存储 编译器
浮点数据类型在内存中的存储以及大小端介绍
浮点数据类型在内存中的存储以及大小端介绍

热门文章

最新文章