整型、浮点型在内存中的存储

最近学习了有关整型和浮点型在内存中的存储以及如何使用。
并展示了几道很有价值,有意思的题。
欢迎大家一起学习,相互进步。

一、数据类型

在c语言中有整型、浮点型、构造类型、指针类型等。

整型:

char
unsigned char
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]

浮点型:

float
double
long double

构造类型:

数组类型
结构体类型 struct
枚举类型enum
联合类型 union

指针类型:

int * pi;
char * pc;
float * pf;
void * pv;

空类型:

void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。

类型的意义在于:

  1. 使用不同的类型决定了开辟空间的大小
  2. 决定了如何使用内存空间

二、整型在内存中的存储

知道了一个变量的类型,就知道可以开辟的空间的大小。
那例如int型具体是如何在内存中进行存储的呢?
需要了解下面的概念:

1.原码、反码、补码

计算机中的有符号数有三种表示方法,即原码、反码和补码。
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位
三种表示方法各不相同。

原码
直接将二进制按照正负数的形式翻译成二进制就可以。

反码
将原码的符号位不变,其他位依次按位取反就可以得到了。

补码
反码+1就得到补码。

正数的原、反、补码都相同
对于整形来说:数据在内存中存放的都是补码。
原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。


看看在内存中的存储:
按照推理,a的补码应该是0000 0014,b的补码应该是ffff fff6
而在内存中所存储的形式有点不一样,这可能就得了解大小端的概念了
在这里插入图片描述

2.大小端

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

从图中可以看出这台电脑是小端存储的,因为它数值的低权值位存储在低地址处。

三、知识运用

1.了解隐式类型转换

不了解隐式类型转换的铁汁戳这里
->什么是隐式类型转换<-

2.例题练习

//输出什么?
#include <stdio.h>
int main()
{
    char a= -1;
    signed char b=-1;
    unsigned char c=-1;
    printf("a=%d,b=%d,c=%d\n",a,b,c);
    return 0; }

结果:
在这里插入图片描述
解析:

首先-1是整型常量,在32位下的补码是1111 1111 1111 1111 1111 1111 1111 1111 ,在存入char型变量时发生截断,所以在内存中存入a b c的数据都是1111 1111,是一样的,这是因为数据的存入和目标变量没有关系,目标变量只提供存储空间。
printf也是函数,传参就要发生值拷贝,就需要用到CPU,也同样就会发生隐式转换。
ab都是有符号字符型,发生整型提升时补上对应的符号位,即1111 1111 1111 1111 1111 1111 1111 1111,还是-1的补码,按照%d的有符号整数进行打印时,就是-1。
c变量是无符号字符型,在进行整型提升时默认补0,也就是0000 0000 0000 0000 0000 0000 1111 1111,按照%d进行打印后是255

#include <stdio.h>
int main()
{
    char a = -128;
    printf("%u\n",a);
    return 0; }

结果:
在这里插入图片描述
分析:
在这里插入图片描述

#include <stdio.h>
int main()
{
    char a = 128;
    printf("%u\n",a);
    return 0; }

结果:
和上一题一样,因为128和-128发生截断后在a里存的数据是一样的

    int i = -20;
    unsigned int j = 10;
    printf("%d\n", i + j);

结果:
在这里插入图片描述
分析:
在这里插入图片描述
因为并没有对两个变量的数据进行修改,想加过后按照%d的结果就是两个数直接相加的结果

    unsigned int i;
    for (i = 9;i >= 0;i--)
    {
        printf("%u\n", i);
    }

结果:
死循环,从9->0->255->0->255,因为无符号数始终大等于0

int main()
{
    char a[1000];
    int i;
    for(i=0; i<1000; i++)
   {
        a[i] = -1-i;
   }
    printf("%d",strlen(a));
    return 0; }

结果:
在这里插入图片描述
分析:
在这里插入图片描述

#include <stdio.h>
unsigned char i = 0;
int main()
{
    for(i = 0;i<=255;i++)
   {
        printf("hello world\n");
   }
    return 0; }

结果:
死循环,i 的值从0->255一直循环

四、浮点型在内存中的存储

浮点型:

float
double
long double

1.浮点数的表示

任意一个二进制浮点数V可以表示成下面的形式:

  • V = (-1)^S * M * 2^E
  • (-1)^S表示符号位,当S=0V为正数;当S=1V为负数。
  • M表示有效数字,大于等于1,小于2
  • 2^E表示指数位。

举例说明:
十进制的5.0,写成二进制是101.0 ,相当于(-1)^0×1.01×2^2 。 那么,按照上面V的格式,可以得出S=0M=1.01E=2
十进制的-5.0,写成二进制是-101.0 ,相当于(-1)^1×1.01×2^2 。那么,S=1M=1.01E=2

2.浮点数的存储结构

对于32位的浮点数

最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。

对于64位的浮点数

最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。

3.如何存储浮点数

在计算机内部保存S时
浮点数是负数就保存1,是整数就保存0,和整数保存符号位的规则一致。

在计算机内部保存E时

因为E为一个无符号整数(unsigned int),如果E为8位,它的取值范围为0 ~ 255;如果E为11位,它的取值范围为0~2047。

但是,在科学计数法中的E是可以出现负数的,所以有规定将,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127,所以E能存储的范围为[-127,128];对于11位的E,这个中间数是1023,所以E能存储的范围为[-1023,1024]

比如,就拿上述提到的5,2^2的E是2,所以保存成32位浮点数时,必须保存成2+127=129,即1000 0001。而取出来时,再减去127,拿出来的时候还是2。

这样做的好处就是可以用无符号数保存有符号数,存的时候既不影响存储,拿出来又不影响使用,这样就可以方便计算。

E的几种特殊取值

  1. 当E全为0时,根据上述的计算方法,存入的数为0 - 127 = -127,可以看出此时为E的取值为最小,并且2^(-127)是一个相当小的数,所以就可以规定-2^-1262^-126两者之间的区间为0(M取最大值为2),凡事在这个区间里的float浮点数都可以被认作0,double的零区间更小,更精确。0的范围取定不确定,在不同的工程中有不同的区间的划定,只是这里选择这个比较直观的区间。
    需要注意的是,浮点数判断两个数是否相等,就不能简单的用==表达,而是要判断该数是否落在规定作为0的区间。
  2. 当E全为1时,E的数值最大,存入的数为255 - 127 = 1282^(128)是一个相当大的数,当M取2-2^-23-2^128×M ~ 2^128×M就是float的最大取值范围。

double类型的取值范围以此类推

在计算机内部保存M时
采用标准科学计数法时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的小数点部分。
比如保存1.01的时候,只保存01,并按照居左对齐,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。
带来的好处就是,以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。

4.例题练习

看我直接上代码

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;
}

结果

分析

  • n为int型,在32位下分配的空间为四字节,整型常量9在该空间下的存储为0000 0000 0000 0000 0000 0000 0001 0001,所以在按整型打印结果就是9。当pFloat指针以float浮点型打印时,看待该空间下存储的数据的方式就会发生变化,可以看出通过浮点数的方式看待内存中的数时,这时它小于2^-126
  • 当通过浮点型pFloat指针对n的值进行修改后,n空间存储的内容为0 1000 0010 0010 0000 0000 0000 0000 000 ,此时如果用整型解释该内容就会是一个很大的正数。
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bruin_du

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值