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

在前面的篇博文中,我们讲解整数和浮点数在内存中的存储结构

参见
深入理解计算机系统-之-数值存储(四)–整数在内存中的存储方式

深入理解计算机系统-之-数值存储(五)–浮点数在内存中的存储方式

代码上传至
https://github.com/gatieme/AderXCoding/tree/master/language/c/storage

浮点数写,整数读


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

代码示例


我们对上一篇文章中修改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×20=1.001×23
阶码=3 +127 =130 =10000010B

符号位阶码尾数
01000001000100000000000000000000

存储起来就是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);

会进行如下处理

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

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

因此打印的结果始终为0

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


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

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

因此显示的结果是9

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


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

符号位阶码尾数
0100001100110010001000000000

小端模式的存储结构为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;
}

这里写图片描述

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值