1:大小端存储
我们知道数据在内存中都是有地址指向的,那么一个整形的数据到底是怎么存储的呢
我们打开内存监视窗口可以看到
二进制 00000000 00000000 00000000 10000000--->a
十六进制 00 00 00 80--->a 80被存储在低地址中,高位都是0,都存储在高地址中。
这种存储方式被称为 小端存储:
数据的高位存储在高地址中,数据的低位存储在低地址中。
与之对应的大端存储 :
数据的高位被存储在低地址中,低位被存储在高地址中。
2:在c语言中,有两大类型的数据
2.1:整形数据
1 char 2 short 3 int 4 long int
( char: 字符在内存中都是以ascll码进行储存,所以他是属于整形的范围。)
#include<stdio.h>
int main()
{
int a = 128;
char b = 1;
int c = a + b;
char d = a + b;
printf(" %d\n", c);
printf("%d\n", d);
printf(" %u\n", d);
return 0;
}
//运行结果
//129
//-127
//4294967169
int a=1;
系统会先生成: 00000000 00000000 00000000 10000000这样的一个二进制数
因为是一个正数,所以他的源码,反码,补码相同,而a是一个int类型的变量,也正好可以存下这32个比特位。
00000000 00000000 00000000 10000000--->a
int b=1;
系统会先生成: 00000000 00000000 00000000 00000001这样的一个二进制数
因为是一个正数,所以他的源码,反码,补码相同,
但是这里b的类型是一个char类型的变量,他里面只能存8个二进制位,所以这里会发生截断,最低的8个二进制位被放入了b中。
000000001 ---> b
int c=a+b;
寄存器在进行运算时,(寄存器的大小一般是int类型的大小)char 类型的b他只有8个位,这里就会发生整形提升,提升到32位,(如何提升在我之前博客有讲)
00000000 00000000 00000000 10000000--->a
00000000 00000000 00000000 00000001--->b
00000000 00000000 00000000 10000001--->c
c中放的就是 00000000 00000000 00000000 10000000;
后面以有符号整形的形式打印 “%d”,所以c打印出129.
char d=a+b;
以有符号整型打印d
这里a和b在寄存器中的运算都是一样
00000000 00000000 00000000 10000000--->a
00000000 00000000 00000000 00000001--->b
00000000 00000000 00000000 10000001
但是因为d是char类型变量,所以会发生截断,b中存的是 10000001
他以有符号整形形式打印“%d”,因为他是char类型变量,这里又会进行整形提升。
而最高位的1,代表他是负数前面补符号位1,
(补码到源码,和源码到补码的方式相同)
11111111 11111111 11111111 10000001--->补码
10000000 00000000 00000000 01111110 ---
10000000 00000000 00000000 01111111--->源码(打印出来的数)
最高位1代表负数,最低7位表示127.
所以结果位-127.
以无符号整型打印d:
这里a和b在寄存器中的运算都是一样
00000000 00000000 00000000 10000000--->a
00000000 00000000 00000000 00000001--->b
00000000 00000000 00000000 10000001
但是因为d是char类型变量,所以会发生截断,b中存的是 10000001
他以整形形式打印d,因为他是char类型变量,这里又会进行整形提升。
而最高位的1,代表他是负数前面补符号位1,
(补码到源码,和源码到补码的方式相同)
11111111 11111111 11111111 10000001--->补码
10000000 00000000 00000000 01111110 ---
10000000 00000000 00000000 01111111--->源码(打印出来的数)
但是要注意这里是以%u来进行打印d,无符号整形在操作时没有符号位的概念,系统不会将最高位看成符号位,所以最后打印出了一个很大的数。
2.2:浮点型数据
他的存储方式是不是和整形的存储方式相同呢,下面我们通过一个示例来看一下
从这个例子我们可以知道,整形和浮点型数据的存储,和取出方式都不相同。
浮点型数据的存储(只限c语言)
根据IE754标准,任何一个二进制浮点数 x 都可以表示成下面这种形式
(-1)^s*M*2^E,
这里的s M E 的作用形式如下:
(-1)^s s表示符号位,s=0,表示正,s=1,表示负
M 表示有效数字(M必须满足的条件1<=M<2)
E 表示指数位
浮点数 5.5 十进制
101.1 二进制 <=>(-1)^0*1.011*2^2,
s=0 m=1.011 e=2
所以说,只要知道这三个值,就可以表示任何二进制下的浮点型数据
浮点型的32位二进制位中被分配给了 s(1个比特位) e(8个比特位) m(23个比特位)
这里详细说一个E 位的放置和M位的放置
1:E是一个size-t形式的数据,但是如果要将0.5放入一个float型数据的话
十进制 0.5 0.5<=>1*2^-1;
二进制 0.1(这个1的权重是2的-1次方)
所以我们需要E是一个负值,但是定义里E是一个无符号数,所以在对E中数据进行存储时,会对它先加上一个127(float型) 或者1023(double),拿出的时候再减去。
2:M位置的放置
因为M必须大于等于1,小于2,所以在对M数据进行放置的时候,会将小数点前面的那个1不放入M的中,拿出的时候加上进行了。
知道这些我们就可以对开始的那个例子进行解释了
a=9
将9放入a中
00000000 00000000 00000000 00001001-->a
所以说a中存储的应该是这样的一串二进制码,但将其以float形式打印,s=0 e=00000000-127 (这里当e全为0时,拿出时e=1-127)=-126 m=00000000 00000000 1001
所以,用float形式打印出的a要乘以应该2的负126次方,这个结果无线接近于0,而float小数位只有6位,所以打印出全0.
*pa=9.0
将9.0以float形式存入内存中
0(s位) 00000011(E位) 00100000000000000000(M位)
而将这个数以整形的形式打印,那么编译器就会用拿出整形数据的方式拿出这个数据,所以就会得到一个很大的数。
最后要注意一个点:
在上面整形的数据以浮点型数据打印的时候(或者浮点型数据以整形形式打印的时候)
一定要取地址然后进行强制类型转换,才能输出结果,不然只会输出0。
不然直接:
printf("%f\n", b);
printf("%d\n", a);b是一个整形数据,也是以整形的形式拿出来的,但是却要以浮点型的类型进行输出,就会出错。
对float类型变量的地址进行强制类型转换成int类型的地址后,打印时,才能对一个原本是以float类型存储方式的存储数据,才能以整形的形式打印。(同理int也是一样)