了解变量的储存原理是我们灵活运用和防止数据截断改变带来的危害的有效途径。
那么我们从int char和float double两类来阐述内存的储存。
首先我们讲内存单位:
内存单位从小到大分别是bit byte KB MB GB TB PB。
bit是最小的内存单位,它可以存储一个二进制,可以表示两种情况0/1。
byte是字节,1byte=8bit 。计算机的内存可以以字节作为一个一个的整体,每一个字节都有一个地址(这里以64为进行举例)
KB就是1024个字节 ,MB就是1024个KB,1MB就是1024个GB,后面也是如此。
(我们在写程序的时候,一般更多关注的是比特字节。)
值得注意的是,任何数据在内存种都是以补码的形式存储的。
然后我们讲int char这两种类型
学会后,long,short也是水到渠成的事情。
我们先以内存较小的char来看:
char占一个字节,这个字节所对应的地址就是char的地址。char在一般的编译器里是表示signed char,我们要表示无符号的char要用unsigned char。
char是如何储存数据的?
我们将1个字节展开,就有8个字节来存储。
那么就可以存储2^8个数据,也就是256个数据。
char原本是储存二进制的,是通过ascll码来转换字符的。我们如果用%d来打印,就能打印十进制的ascll码值。
我们分别从正数和负数来讨论:
正数:
从00000000到011111111(127)因为都是正数,所以在计算机源码就是补码。也就是这样储存的。
负数:
而10000001并不是表示-1,表示的是补码,我们还要取反加1或者减取反。随便用一种方法,我们先-1得到100000000然后除符号位取反得到11111111,最终表示的是-127。
如果我们再将10000001减1呢?
得到100000000这个似乎不好求源码,其实这个由计算机规定了,表示-128。
那么我们用一个环来表示有符号char的数据存储:(顺时针补码++)
对于无符号的就是水到渠成的事情:
int是四个字节,四个字节是连续的内存的,它的全名是叫signed int 表示有符号的整形。
我们在对一个int类型的变量进行取地址的时候,拿到的是最低的那个地址
例如上图,int这个int 的地址就是 0x0000000000000001,那么我们如何再次拿到这四个字节呢?当然就是指针类型来决定的。对应的指针类型可以访问对应字节数的内存
int如何储存数据的呢?储存范围是什么?
我们将四个字节展开,就有32个bit。每个bit可以表示两种情况,根据二进制数我们可以知道int可以存储2^32个数据。
那么int是有符号的,符号正负是两种情况,因此int 有一个bit来存储符号,31个bit存储数据。
它和char的储存方式是一样的,这里我就不再啰嗦,大家自己类比。
float和double的数据存储:
浮点数因为有小数点,所以用之前的方法存储就不太现实。
那么就出现了另一种方法:
我们以float来进行讲解,然后double储存是类似的。
首先我们数学中有种数据的表示方法:科学计数法。而我们存储float,double也是差不多的。
-1000.86我们可以写成 (-1)^1 * 1.00086 * 10^3;
10.24我们可以写成 (-1)^0 * 1.024 *10^1;
那么我们把十进制改成二进制:
5.5我们写成二进制:101.1-> (-1)^0 * 1.011 * 2^2
那么我们推广到任意形式: (-1)^S * M * 2^ E
我们只要存储S M E 就行了。
其中E的取值范围是1<=E<2这样保证了E全是1.什么,那么我们就可以将1省掉,只保存小数点后面的数据,这样就可以增加我们的精度。
为什么说叫增加精度呢?因为我们的float和double都是无法都精确保存数据的。我们小数点后一位数是1/2,后第2位数1/4,后第三位数1/3,这导致一些数是无法精确保存或者要很长的二进制数组来保存。
下面是double的储存形式:
因为浮点数和字符形整型数不同。我们在整形数、字符之间强制类型转换还有可能保证打印的数据不出错,但是我们如果拿给浮点数就彻底出错了。