【C进阶】第八章-数据的存储

为什么整数数据在内存中存的是补码?

为了简化计算机基本运算电路,使加减法都只需要通过加法电路实现,也就是让减去一个正数或加上一个负数这样的运算可以用加上一个正数来代替。

char在内存中存的是整形

signed char 的范围是 -128~127

00000000

00000001

…………

01111111 //0~127

10000000

10000001

…………

11111111

10000000//-1~-128

补码 

其实就相当于:
超出范围时,对最大值取余

比如说无符号char 存了个256 实际上对应的就是256%255=1,余了个1相当于范围的第一个,根据起始的范围不同而不同。0-255 所以余1就是对应0,256在unsigned char 中存的是0。 

unsigned char 的范围是 0~255

数据范围是多少就看bit位数有多少。

大小端字节存储:

大端字节存储:位字节处数据存放在高地址处位字节处数据存放在低地址处

小端字节存储:位字节处数据存放在低地址处位字节处数据存放在高地址处

练习

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

char 跟signed char unsigned char 实际上在内存存的补码都是一样的,区别在于:

整形提升时,无符号char会按0补位;有符号char按符号位补位

打印时,按u打印,按c打印,即不需要补位时:

哪怕是无符号char也可以打印出有符号有符号char也可以打印无符号

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

思路

char a = -128
-128原码:10000000 0000000000 0000000000 10000000
    反码:11111111 11111111 11111111 0111111
    补码:11111111 11111111 11111111 1000000
存到char类型的a中需要截断

即a中的补码为:100000000

题目中%u为整数格式,因此打印的时候需要整数提升
而a又是有符号char,因此前面补符号位
a提升后的
    补码:11111111 11111111 11111111 10000000

%u为无符号,因此补码即原码,直接打印
转为10进制就是4294967168
结果应为4294967168

浮点数在内存中的存储

        接下来根据一串代码来理解浮点数在内存中的存储。

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的地址转成float* 存放在pFloat里

float指针解引用时,会认为内存放的是float型数据,打印时结果是0.000说明浮点型存储方式跟整形不同。

可以这样理解

第二、四:以浮点型方式从内存拿出来。

第一、三:以整形方式从内存拿出来。

前两句在内存中是按整形存放,后两句是按浮点型方式存放。

第二句在内存整形数据以浮点型方式取出,输出的数据不是9.0;

第三句在内存浮点数据以整型方式取出,输出的数据不是9。

综上说明浮点型数据跟整形数据的存储方式不同。

根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:

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

如 5.5,表示为(-1)^0*101*2^2

小数位的二进制如下:

小数的二进制
    0.1------->2^(-1) = 1/2^1 (0.5)
    0.01------>2^(-2) = 1/2^2 (0.25)
    0.001----->2^(-3) = 1/2^3 (0.125)
    0.0001---->2^(-4) = 1/2^4 (0.0625)

 因此小数位一个1,就表示1/2=0.5

转为科学计数法,M*2^E,小数点向左移动几位E就等于几,相当于20变成2*10^1

浮点数在内存中可能没法精确保存,比如存3.14,小数位的二进制可能无限逼近0.14而又没法准确的存入。

IEEE 754规定:
对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。

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

 对于E,存放的数据是无符号数据,但E是有可能为负数的,因此规定8位的+127再放进去   11位的+1023再放进去

比如0.5转成二进制:0.1,再按科学技术表示 →(-1)^0 * 1.0 * 2^(-1)

S=0

E=-1,加上127=126,再存进去(二进制为 01111110)

M=1.0  (23位)

存放:S:0  E:01111110   M00000000000000000000000

0.5在内存存储的二进制:00111111000000000000000000000000

E全0表示无穷小:E=1-127=-126,就是2^(-126),是非常小的数(-127相当于还原)

E全1表示无穷大:E=255-127=128,就是2^(128),是非常大的数

回到之前的练习,int 9在内存中存的是000000000 00000000000000000001001

第二条用float方式取出,那么上面的补码被解读成

S=0,E=00000000(8bit),M=0.00000000000000000001001

即:(-1)^0* 0.00000000000000000001001 *2^(-126)

而float打印时打印到第6位,而此时小数已是无限接近0的数字,根本找不到后面的有效数字,故最后打印的是0.000000

再看float 9.0,在内存中存的是 1001.0→ 1.001*2^3

S=0,E=3,M=001(舍去小数点前的1)

按规定存进内存:E+127=130,M后面补20个0 (23bit)

0 10000010 00100000000000000000000

浮点数的存储以浮点型方式拿出,是没有问题的。第三条以int型拿出,因为是正数,原反补码相同,通过计算器换算得到结果1091567616,跟运行结果一样。

浮点数的比较

        浮点数因为精度问题,是没法直接和某些数比较的。

float f=0.12;
if(f==0.0)

参考【详解】浮点类型的存储及比较_Yang-FS的博客-CSDN博客_浮点型比较

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值