Contents

以下数字可能出现的比较频繁,我们先记住一些常用的数字:

  • 计量单位

2^10^ = 1024 = 1K
2^20^ = 1048576 = 1024K = 1M
2^30^ = 1073741824 = 1024M = 1G

  • 常见数字

2^8^ = 256
2^16^ = 2^8*2^ = 65535
2^32^ = 2^8*4^ = 4294967296 = 4G
2^64^ = 2^8*8^ = ??

我们知道计算机是由2进制来储存信息的,我们把一个2进制数位看成一个灯泡,它要么是亮的状态(1),要么是暗的状态(0),那么我们把这个灯泡叫做「位」,英文用bit(比特)表示。但是位的表达有限,我们用一个更大一点的单位来作为基础单位,那就是字节Byte(拜特)。一个字节就是8位,

【灯泡1-灯泡2-灯泡3-灯泡4-灯泡5-灯泡6-灯泡7-灯泡8】 这样8个一串的灯泡就是一个字节,我们说的什么KB,GB的B就是这个字节Byte。而小区墙上贴的各种广告上说的什么10兆100兆带宽指的是位,比如10Mbps / 8(b/位) = 1.25MBps (1.25M/s)

1个字节能表达多少信息呢?如果换成10进制数就是2^8^=256,就是说一个字节能存下范围为0~255的一个数字。那你可能会问,我为啥要存这样一个数字,我不能存2^4^=32,即0~31的两个数字吗?或者拆成其他的分等来表达行不行?

答案是行,但是又不行。1字节的数字甚至可以表达8个布尔值(bool值的意思就是只能为真或假,就是值只能为1和0),比如一家有8口人,0~255的数字可以完全记录这家人的性别,比如1是男0是女,8个灯泡暗或者灭的所有排列组合,都对应了其中一个数字,倒过来反推也可以,1一个0~255的数字,可以推出这家8口人的性别。

1个字节能表达的数字不大,那他能干什么呢?我们来学习第一个数据格式,叫做char。char是什么意思呢,就是字符的意思。观察一下我们手里的键盘,大小写字母符号乱七八糟加起来有多少?,是不是64个不够,256个又太多?刚好差不多不超过128个?所以一个char就能够表达英语环境中的一个基础字符(0~127)。为什么我这里要强调它的环境呢?因为要输入其他的特殊字符,1个字节就不够了。但对于最初最初的计算机来说,表达一个字符一个char就够了。

我们上面说不行的原因,就是我们用了一个char来表达一个字符,那它作为char的话已经用了一个字节来表达所有的信息,哪怕它只用了一半。(我的意思就是说计算机就是这样的,有一个东西要什么东西你就只能给或者不给,给多了的东西你也没办法拿回来。有的游戏上来就直接申请2G的运行内存,哪怕它其实只是一个扫雷,但是你的电脑就是少了2G可用内存,电脑配置不行的话就卡成弱智,虽然你也不理解为什么,我只是开了一个不能再小的扫雷而已。)

你可能会发现,127不就是刚好少了1位吗,那还有一个灯泡空着不是浪费电吗?这个灯泡其实是有用的。char取值为0-127的时候能代表一个字符,但是一定要记住,char的「本质」上还是一个数字。当我们定义了一个「char」的时候,它的第一位就变成了符号位,后面7位才是数值。所以它代表的数值范围其实是-128~127,共256个数字。

为什么是-128~127呢?这个符号位当它是0的时候,就代表它是一个正数,意思就是我灭了,两眼一闭高高挂起,你们其他几个爱咋咋地,原来是多少就是多少,所以还是原来0~127。当它是1的时候,就是代表它是一个负数,就需要把后面的值加个负号变成-0~-127。-0那就看做最大负值,也就是-128。

如果我们需要表达0~255的值的话,我们需要定义「unsigned char」,unsigned的意思就是无符号,整个意思就是无符号字符,也可以说是无符号字节,因为我们日常中很多数字都是自然数,不会出现负数,那这样我们就不需要符号位了,那unsigned char就能够表达128~255的数字。两个类型能够表达的数字都是256个,是一样的。

我们还有其他的数据格式,整数的有short,int和long long(短整型,整型和长整型)以及对应的无符号类型(unsigned short,unsigned int和unsigned long long),它们分别占了2个,4个和8个字节。你可能会问,为什么没有6个字节的呢?你可以把这些数据想象成大小不一的砖头,把程序看成最后的建筑,1:2:4的砖头肯定比1:2:3的砖头来的号,为什么?因为他们在内存里能够一一「对齐」,内存对齐这个思想贯穿了整个图形学,总的来说会有很多好处,比如效率高,计算快等。

这里有一些等价表达问题,这边可以说下:
short = short int = int16
int = long int = long =
int32
long long = long long int = __int64

我们可以简单计算下,short能表示带符号的3万多(2^15^),int能表示带符号的21亿(2^31^),long能表达的数字更大(2^63^),可以理解为42亿个int那么大。在我们列出小数的数据格式之前,我们先提出一个设想。

假设我和你在一起计算机考试,你完全不会里面的内容,但是你知道我的答案肯定是对的,那你要怎么作弊才能确保满分呢?你可以偷偷看我的卷子,然后每一条都抄上答案。但是还有一种更简单的方法,就是直接拍张照片,打印了交上去啦!两个人最后都是满分!

这两种方法有什么区别呢?第一个是值相同,第二个是址相同。什么意思呢,虽然两个方法最后的效果都是一样的,但是第一个卷子是你做的,第二个卷子相等于两张都是我做的。所以你想表达一个和现有值相同的方法,除了先在地上划出一块和原有值相同的大小,然后照模照样的搭房子,还能干脆在地上插一个路标,上面写着「去找他」!这个牌子实际上就是表达了一个地址。这的一个地址,我们叫做指针(pointer)。

那这样一个地址在计算机里怎么表达呢?当然用数字就够了。在我这个世代还接触过32位(×86)的电脑,现在都是64位(×64)了,当然现在要创建一个程序有时候还要确定是32位的还是64位的。我们可能知道64位的电脑可以跑32位的程序,反之就不行。那这个位是啥意思呢?这就是代表了指针的大小。

32位有多大?4个字节,2^32^ = 2^8*4^ = 4294967296,刚好就是4G。换而言之,32位的电脑内存不可能超过4G。在零几年的时候电脑内存还在几百M的时候,4G看起来还是非常遥远的目标,更早的时候甚至更小,以K为单位。这个时候插内存条有用吗,就没用了。就好像你拿着福建的地图到了浙江一样,这块地方你就管不了了。64位的电脑的内存上限就很大了,按上面说的相当于几十亿个4G的内存条,这样在相当长的一段时间内,计算机都不需要再改架构了。

那么所有的指针都是等价的吗?是的,本质上就是一个正整数,无数的指针可以互相随意转换。

它不管是指向一个几百亩的豪华别墅,还是指向一个半米宽乡间厕所,它本身就是一个地址,存的就是相同长度的数字。用刚刚的考试作弊做个例子,如果我们想交换答案,除了互相看卷子重新填写以外,是不是直接交换卷子就可以了?对!这样既简单又符合我们的直觉。那你可能会想到一个问题,如果你想那你的厕所换我的别墅,除了把两边都拆了重建以外,是不是只要交换我们的地址就可以了?我知道这很反直觉,但并不可行。

如果我们直接交换了地址(&),你能拿到的只能是这个别墅的前半平米,可能连大门都还没到,而我拿到的除了这个半米的厕所,还有剩下几百亩的地。这个地上有什么?不知道,可能是一片无垠的荒地,也可能存在别人的房子。计算机会把这部分整个看做是我的别墅,这明显是不合理的,其他的房主会来打我。即使是重建,你也需要重新申请一大块土地。本质上来说,我们拥有的不是同一个东西(类)。

但是!如果我们房子不是买的,是租的,我们拥有的只是两个房子的带住址的名片(指针),那我们直接交换行不行?OK!我们交换了名片以后以后你只要告诉计算机,我拿到的已经不是厕所了,是一个大别墅!这样计算机就会用大别墅的方式去解析你的地址,这样你就住进了大别墅!

假如你要拆房子,那又该怎么做?第一,把你的地址交给施工队,施工队按照你的房子说明的大小铲平了这块地,然后你应该把你的这个地址撕掉,因为它不再有用了。无用的数据残留在内存中没有及时释放,他们管这叫做内存泄漏,说白了就是钉子户。

Contents