整形数据在内存中的存储
一、对于整形,数据存放在内存中的是补码(二进制)。
正数的原码,反码,补码都相同,比如int a=1; 则a的原,反,补码都是:00000000000000000000000000000001。对于负数,原码是符号位为1的二进制表示,反码要对除符号位外按位取反,补码就是反码加1。例如:int a= -10; 则a的存储为:
原码:10000000000000000000000000001010;
反码:11111111111111111111111111110101;
补码:11111111111111111111111111110110。
二:大小端字节序与字节序判断
对于字节内容的存储涉及大小端的知识。现在 int a=0x11223344;那么a的存储就要占4个字节(与类型有关),在内存中从低地址到高地址,字节内容存储的顺序不同。
①大端字节序存储:将一个数据的低位字节内容存放在高地址处,高位字节的内容存放在低地址处。a从低到高地址依次存放 11 22 33 44。
②小端字节序存储:相反,低位字节在低地址处,高位字节在高地址处。a从低到高地址依次存放 44 33 22 11。
采用大端还是小端存储,与机器有关,以下代码可以判断机器是用何种方式:
#include<stdio.h>
int main()
{
int a=1;
if(*(char*)&a==1) //取出a的第一个字节进行判断
pritnf("小端");
else
printf("大端");
return 0;
}
三、举例
char a=-1;
signed char b=-1;
unsigned char c=-1;
printf("%d %d %d",a,b,c);
以上代码输出的结果将是:-1 -1 255
这是因为-1的原码是10000000000000000000000000000001,存储的补码是11111111111111111111111111111111,然后再看类型,char a只能储存8个bit位,需要发生截断,故a就是11111111,而b,c也是11111111。又%d是以十进制打印有符号整数,需要整形提升,a,b类型都为有符号,按符号位进行提升,补1,均变成:11111111111111111111111111111111,是-1;c为无符号类型,整形提升时补0,最后是:00000000000000000000000011111111,也就变成了255。
浮点数在内存中的存储
一、任意二进制浮点数V可以表示成如下形式: (IEEE754规定)
其中,s如果取0,就表示正数,取1,就表示负数。M是有效数字,M的值满足大于等于1,小于2。2的E次方表示指数位。例如,十进制的5.0,二进制是101.0,也就是1.01*2²,那么对应的s就是0,M=1.01,2的E次方即是2²。
IEEE754还规定,32位浮点数,在内存中最高的一位存储S,接下来的8位存储E,剩下的23位存储M;64位浮点数,最高的一位存储S,接下来的11位存储E,剩下的52位存储M。
再举一个特别的例子:十进制的0.5,其二进制表示是0.1,也就是1.0*2的负一次方与常规的换算稍有差异,另外,这也说明真实的E是有可能出现负数的。
二、存的过程与取的过程
①因为M的第一位总是1,所以在存储时就可以省略,只存小数点后面的数据,0.xxxx...,取出时再补上小数点和1。
②真实的E可能出现负数,就不利于存储,在存入的时候需要加上一个中间值。对于8位的情况,中间值是127,1位中间值是1023。
③取的时候,二进制的E如果既不全为0,也不全为1,就直接减去127(or1023)取出;如果全为0,E就是-127(或者-1023);如果全为1,这时如果M全为0,就表示正无穷或负无穷。
三、小结
根据以上浮点数存储的规则,可以知道并不是每一个小数都有刚好可以凑成的二进制表示,有些浮点数在内存中是无法精确保存的;double类型数据的精度将比float类型的更高;两个浮点数比较大小的时候,直接用“==”比较有可能出现问题!往往需要自行设定一个精度。