目录
1.1 unsigned char和signed char在内存中的取值范围
二. 浮点数在内存中的存储(浮点数在float.h头文件中定义)
1.1 unsigned char和signed char在内存中的取值范围
unsigned char 和 signed char 的取值范围,如下图所示:
<1>
signed的取值范围为:-128 ~ 127
<2>
unsigned char的取值范围为:1 ~ 255
同理:signed short -32768 ~ 32767 unsigned short 0 ~ 65535
1.2 整型存储的练习
例1:
#include <stdio.h>
int main()
{
signed char b = -1;
unsigned char c = -1;
printf("%d,%d", b, c);
return 0;
}
-1的补码(8位):11111111
可以看到输出的打印形式为%d,所以的先将它们整型提升
signed:11111111111111111111111111111111(前面补原符号)
unsigned:00000000000000000000000011111111(前面补0)
所以输出为:-1,255
例2:
#include <stdio.h>
int main()
{
char a = -128;
printf("%u", a);
printf("%d\n", a);
return 0;
}
-128的补码为(8位):10000000
整型提升之后:11111111111111111111111110000000 然后以%u(unsigned)的打印格式打印就是很大的一个数,以%d的打印格式的话先计算原码在输出
求得原码:10000000000000000000000010000000 得到结果为:-128
例3:
#include <stdio.h>
int main()
{
char a[1000];
int i;
for(i = 0; i <= 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}
该图循环得到的结果是什么?
如下图所示:
顺加逆减(加法就是逆时针,反之则为顺时针)
代码中是 -1 - i即逆时针。经过循环-1, -2, -3, -4, -5, -6.....-128, 127.....1, 0
到0之前有255个数,所以strlen(a)得到的值为:255
例4:
#include <stdio.h>
int main()
{
unsigned char i = 0;
for(i = 0; i <= 255; i++)
{
printf("hello world");
}
return 0;
}
得到的结果是什么呢?
如下图所示:
当循环结束时i=256 即:0
这样循环往复就构成了死循环
例5:
#include <stdio.h>
int main()
{
if(strlen("abc") - strlen("abcdef") >= 0)
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
'>'还是'<'?
从上图可以看出strlen函数的返回值为size_t(unsigned int),两个无符号整型相减结果必然是一个无符号整型,相减得-3,把-3看成无符号整数它将是一个很大得正数
二. 浮点数在内存中的存储(浮点数在float.h头文件中定义)
1.1 浮点数存储规则
num和*pfloat在内存中明明是同一个数,为什么浮点数和整数的解读结果会差别这么大
根据国际标准IEEE(电气电子工程师学会)745,任意一个二进制浮点数v可以表示成下面的形式:
(-1)^S*M*2^E
(-1)^S表示符号位,当S = 0时,v为正数;当S = -1时,v为负数
M表示有效数字,大于等于1,小于2(1<=M<2)
2^E表示指数位
例:
V = (-1)^S*M*2^E
当V = 5.0f时,5.0 --> 101,0 --> 1.01*2^2(M的小数点往左移动了两位)
V = 5.0f = 1.01 * 2^2 = (-1)^0 * 1,01 * 2^2 即:S = 0,M = 1.01,E = 2
小数点的左边从2^0开始,右边从2^-1开始
如图:
当然有些浮点数也不能用二进制精确的获得
如:
V = 9.6f = 1001.1000....00100001... 这样只是无限接近于9.6,根本不准确
float,double这两种浮点数类型都不可能精确的存储有些浮点数,只不过说double精度更高而已
float
IEEE754规定:
对于32的浮点数,最高的1位是符号位S,接着的8位是指数(E),剩下的23位为有效数字M
如图所示:
double
IEEE754规定:
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数(E),剩下的是52位位有效数字M
如图所示:
浮点数存入内存中的方式
<1>.
IEEE754对有效数字M和指数E,还有一些特点的规定,1<=M<2, M可以写成1.xxxx..的形式,其中xxxx表示小数部分
754规定,在计算计内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保留后面的xxxx部分
如:保存1.01时,只保存01,等到读取的时,再把第一位的1加上去。目的,可以节省一位有效数字。以32位浮点数为例,留给M的只有23位
将第一位的1舍去之后,等于可以保存24位有效数字
<2>.
E为一个无符号整型(unsigned int)
如E为8位,它的取值范围位0 ~ 255,如果E是11位,它的取值范围为0 ~ 2047存储进内存的值不能超8位或11位的取值范围
科学计数法中E的真实值是可以出现负数的,所以IEEE754规定,存入内存时E的真实值必须再加上一个一个中间数,对于8位的E,这个中间值是127,对于11位来说,中间值是1023
当E为10时,保存成32位浮点数时,必须保存成10(真实值) + 127(中间值)=137即:E为10,但是保存在内存中的数为137 ---> 10001001(以二进制存在内存中)
当E为-1时,即-1 + 127 = 126 --> 01111110 //E为8位时 -1 + 1023 = 1022 //E为11位
例1:
V = 0.5 = 0.1 = 1.0 * 2^(-1) = (-1)^0 * 1.0 * 2^(-1)
S = 0 M = 1.0 E = -1(因为M < 0不符合范围,所以往右移一位,即E = -1)
例2:
float f = 5.5;
5.5 = 101.1 = 1.011*2^2
(-1)^0 * 1.011 * 2^2
S = 0 M = 1.011 E = 2^2
将S,E,M按顺序放入内存中,如图所示:
浮点数的取出方式
3.
指数E从内存中取出还可以再分成三种情况
(1)E不全为0或不全为1
如例1:
0 10000001 01100000000000000000000
(-1)^0 * 1.011 * 2^(129 - 127)
取出来就是在有效字母M前面加上第一位的1,指数E的计算减去127(或1023),还原真实值
(2)E为全0
这时,浮点数的指数E等于1-127(或1-1023)即为真实值有效数字M不再加上第一位的1,而是还原为0.XXXXX的小数,这样是为了表示正负0,以及接近于0的数字
在内存中E为全0就是E为-127时,将这个浮点数取出就是 1.xxxxx * 2^-127 = 正负(1.xxxxx/2^127)得到的结果是无限接近于0的小数,所以直接按上面的方式求E为全0的结果就可以了
(3)E为全1
这时,如果有效数字全为0,表示正负无穷大(正负取决于符号位S)
如:+-1.xxxx * 2^128 = +-无穷大
1.2 浮点数存储规则例题
例1:
#include <stdio.h>
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;
}
int n = 9;
补码:00000000000000000000000000001001
将&n(int*)强制类型转换为float*
&n中整型的内容就变成了浮点型内容
0 00000000 00000000000000000001001
S = 0,E = 1 - 127 = -126(E全0),M = 0.00000000000000000001001
(-1)^0 * 0.00000000000000000001001 * 2^-126 约等于 0
printf("n的值为:%d\n", n); //输出9
printf("*pfloat的值为:%f\n", *pfloat); //无限接近于0的数
*pfloat = 9.0;
浮点数9.0在内存中的存储形式: 1001.0 --> 1.001 * 2^3
S = 0 --> 0,E = 3 + 127 = 130 --> 10000010,M = 1.001 --> 00100000000000000000000
即9.0以二进制在内存中储存形式为01000001000100000000000000000000
printf("num的值为:%d\n", n); //将浮点型的内容以整型的形式取出跟据以上我们求出的二进制可以看出是一个很大的数
printf("*pfloat的值为:%f\n", *pfloat); //以浮点型的方式取出