c语言复习进阶 1)数据在内存中的存储

数据在内存中的存储

整型在内存中的存储

计算机中的符号数有三种表示方法,即原码,补码,反码,三种表示方法均有符号位和数值位两部分,符号位用‘0’表示正,用‘1’表示负:

原码

直接将二进制按照正负数的形式翻译成二进制。

反码

将原码的符号位不变,其他位依次按位取反。

补码

反码+1得到补码。正数的原,反,补都相同。

大端小端

在这里插入图片描述

为什么会有大端小端

按照我自己的理解,其实就是计算机是以字节为单位的,每个地址单元都对应着一个字节,为8bit,当寄存器的宽度大于一个字节时,就会出现地址排列顺序的分歧,大端模式就是指数据的低位保存在内存的高地址中,高位则保存在内存的低地址中,小端模式则正好与其相反。

整型提升

在表达式计算时,各种整型首先要提升为int型,如果int型不足以表示则要升为unsigned int类型。

负数整型提升

高位补充符号位1。例:
char c1 = -1; 变量c1的二进制位(补码)中只有8个比特位: 1111111 因为 char 为有符号的 char 所以整形提升的时候,高位补充符号位,即为1 提升之后的结果是: 11111111111111111111111111111111

正数整型提升

高位补充符号位0。例:
char c2 = 1; 变量c2的二进制位(补码)中只有8个比特位: 00000001 因为 char 为有符号的 char 所以整形提升的时候,高位补充符号位,即为0 提升之后的结果是: 00000000000000000000000000000001

无符号整型提升

高位补0。

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

a为负整数,补码为11111111111111111111111111111111,char占一个字节,取低八位,11111111,将a整型提升,高位补符号位1,为11111111111111111111111111111111,%d打印一个有符号整数,取原码为-1.

浮点型在内存中的存储
小数的二进制表示法

例如,5.6,整数部分5用二进制表示为101,
小数部分有这样一个公式,小数部分2,如果<1则为0,基数=基数;如果>1则为1,基数=基数-1,直到基数为0或为循环小数为止。
0.6
2=1.2>1,为1,基数=1.2-1=0.2;
0.22=0.4<1,为0,基数=0.4;
0.4
2=0.8<1,为0,基数=0.8;
0.8*2=1.6>1,为1,基数=1.6-1=0.6;
所以5.6的二进制表示法为101.1001

根据国际标准IEEE745,任意一个二进制浮点数可以表示为下面的形式:
(-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。

  1. IEEE 754规定: 对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
    在这里插入图片描述
    对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
    在这里插入图片描述

  2. IEEE 754对有效数字M和指数E,还有一些特别规定。 前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。
    IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的xxxxxx部分。
    比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。
    以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。
    至于指数E,情况就比较复杂。
    首先,E为一个无符号整数(unsigned int) 这意味着,如果E为8位,它的取值范围为0~ 255;如果E为11位, 它 的取值范围为0~2047。但是,我们知道,科学计数法 中的E是可以出现负数的,所以IEEE 754规定,存入内存 时E 的真实值必须再加上一个中间数,对于8位的E, 这个中间数是127;对于11位的E,这个中间数是1023。 比如, 2^10的E是10,所以保存成32位浮点数时,必须 保存成10+127=137,即10001001。

    然后,指数E还可以再分成三种情况:
    E不全为0或不全为1
    这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M 前加上第一位的1。 比如: 0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1 位,则为1.0*2^(-1),其阶码为-1+127=126,表示为01111110,而尾数1.0去掉整数部分为0,补齐0到23位 00000000000000000000000,则其二进制表示形式为:0 01111110 00000000000000000000000

E全为0
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为 0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
E全为1
这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);

浮点数存储的例子:

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; 
}
  1. printf(“n的值为:%d\n”,n);
    整型的形式打印整型n的值;
  2. printf("*pFloat的值为:%f\n",*pFloat);
    浮点型的形式打印整型n的值;
  3. printf(“num的值为:%d\n”,n);
    整型的形式打印浮点型n的值;
  4. printf("*pFloat的值为:%f\n",*pFloat);
    浮点型的形式打印浮点型n的值

打印结果如下:
在这里插入图片描述
说白了这道题就是整型与浮点型之间在内存中的相互转换,而有一个大前提是,

CPU取数据的时候是按照浮点数的形式取得

当int n=9时,
整型9以%d形式打印,打印结果为9,
而整型9以%f形式打印,也就是先把9转换成二进制,
0000 0000 0000 0000 0000 0000 0000 1001
再将这个二进制数转换成浮点型,这个数的E全为0,s=0,说明它无限正接近0.0000000000
所以打印结果就是0.0000000
在这里插入图片描述
当n=9.0时
首先将浮点型9.0用科学计数法来写为(-1)^0 * 1.0010 * 2^3,,S=0;E为3,3+127=130,转为二进制为1000 0010;M=0010 0000 0000 则9.0在内存中存储结构为:
0100 0001 0001 0000 0000 0000 0000 0000
存的时候E+127,取的时候E-127,
cpu中:0000 0001 1000 0000 0000 0000 0000 0000
以%d打印时E不作处理,转换为十进制为,
1091567616
在这里插入图片描述在这里插入图片描述

发布了34 篇原创文章 · 获赞 4 · 访问量 1756

猜你喜欢

转载自blog.csdn.net/qq_41181857/article/details/101059652