我从无边无尽的黑暗中慢慢醒来,迷迷糊糊,茫然四顾。
耳边传来了风扇卖力干活的嗡嗡声,估计就是他把我吵醒的。 这时候 CPU阿甘 现身了:“兄弟,快醒醒,开机了,要干活了,我要把程序和数据从硬盘读取到你这里来了!”
“放到我这里干嘛?”
“唉,一断电,你什么都忘了,不把程序读入内存,我怎么执行啊?”
奥,对了,我是内存啊,阿甘是我的好朋友,虽然说程序都在硬盘上存着,但是阿甘被设计成只能运行我内存中的程序,所以程序必须要装载进来。
在这个系统里,阿甘最快,我第二, 硬盘则慢如蜗牛,他整天叫嚣着说要提高访问速度,到时候可以把我彻底替换掉, 但是这么多年过去了,还是没有什么进展。
不知道等了多长时间,阿甘终于把一个叫做Linux的操作系统给装载到我这里来了,阿甘说从此以后它就是这里的老大。
可是我却感觉不到老大的存在,我只知道我那一个个电容所代表的0和1 ,由于这些电容不能持久地保持电荷,我得定期地去刷新,如果不及时刷新,那些0和1的数据就会丢失,这将是极为严重的事故,主人就会把我从主板上拔掉,用另外一个家伙来替换我,决不允许这样的事情发生!
次序问题
但是程序员们却不管什么电容,什么刷新,在他们的眼里,我就是一个个的空格子,每个格子对应一个地址,就像门牌号一样。
我最小的一个格子就是一个bit ,只能存储0和1,这实在是太小了, 人们把8个bit 称为一个字节(Byte), 就可以表达2的8次方种可能,从00000000 到 11111111, 如果是无符号数的话,就是0~255。
很明显,Byte还是太小,人们又把更多的字节(比如4个)组织起来,叫做一个Word(字) 。
字节数目一多,就出现了很有意思的问题,比如说有个整数,十六进制的值是0x1234567, 一共是四个字节,那该以什么次序存储他们呢?
一种办法是这样:
还有一种方法是这样:
可笑的是人类为这两种方式争执不休,有人坚决支持大端法,有人则捍卫第二种(即小端法),还有些和稀泥的家伙,大端小端都支持,就看你怎么选择和配置了。
我问CPU阿甘:“如果两个机器的字节次序不同,他们两个通信的时候,岂不天下大乱?”
阿甘叹息一声:“唉,他们在制定TCP/IP的时候,确定了统一的网络次序,使用大端法来传输数据。操作系统老大会提供特定的函数来实现网络和主机之间字节次序的转换,比如 htonl 函数,就可以把32位整数由主机字节次序转换为网络字节次序, ntohl则恰恰相反。 ”
编译器
刚才说到,内存中每个字节都有一个对应的地址,只要能记住这个地址就可以把这个字节的值给取走,或者写入一个值。
比如说,刚才CPU阿甘执行了一些列的指令, 它把地址0x100处的值取出来,和 0x104处的值相加,放到0x110处, 然后再和0x108处的值相乘,结果放到0x10C处。
这一系列操作搞得我眼花缭乱,我对CPU阿甘说:“这程序员真是很厉害,居然能够记住这么多地址!”
阿甘说:“怎么可能? 他们笨得很,根本记不住,全靠了编译器的帮忙。”
“编译器? ”
“是啊,编译器允许程序员用变量的方式来表达程序,它可以把这些变量转换成地址。没有编译器,程序员将会像熊猫一样少。”
- total = base + bonus
- tax = total * rate
原来如此,我这里看到的都是二进制的值,没想到程序员都给他们起了一个名字。
信息 = 位 + 上下文
有一次, 阿甘问我地址0x300的值是多少,我看了一眼,告诉他说是一个32位整数1735159650。
阿甘大惊失色:“兄弟,你睡了一觉什么忘了吗, 你不能擅自去解释你内存数据的类型啊!”
“为什么? 这就是个整数嘛!”
“你这里的值实际上是0x 676C 6F62,他有可能是32位整数1735159650,也有可能是浮点数 1.116533*10^24,还有可能是机器指令呢!!记住!解释权不在你,而在人家应用程序那里,你就管好你电容里的'二进制'就行!”
我觉得很羞愧,这么重要的准则都给忘记了!
信息=位+上下文, 我这里只负责一串串的二进制位,至于这些位的信息是什么,得加上下文才能理解了。
指针
过了一会儿,阿甘问我0x108处存了什么内容, 这一次我不再“解释”了,我告诉他是0x100。
奇怪的是他接下来又问我0x100处的值是什么, 我告诉他说是0x12C, 他这才满意地离开。
我拉着他问道:“你这次怎么了,这么麻烦?还得读两次才行?”
他说:“没办法,程序员用指针了!”
- int i = 300;
- int *p = &i
- total = *p + 200;
“看到没有,这个变量p就表示指针。”
我吓了一跳:“难道我的格子里保存的不仅仅是值,而是地址?”
“是啊,这就再次证明,你不要胡乱解释你保存的值。 我告诉你,有时候还会出现二级指针呢。”
- int i = 300;
- int *p = &i ;
- int **pp = &p;
这真是颠覆了我的认知,我还是刷新我的电容去吧!
不过,在亿万次的读写操作中,我通过这些指针的关系,也发现了一些独特的模式,比如说我发现这样的东西很常见:
我问阿甘:“这是在干嘛? ”
“这就是程序员实现的链表啊。”
“ 那这个东西呢?”
阿甘说:“这不就是一颗二叉树嘛! 程序员管这些东西叫做数据结构。”
我原来以为,我就是一个大数组而已,没想到通过指针,可以表达各种各样的复杂的数据结构的,只要你能沿着指针来回跳转就行。
但是我心里隐隐觉得不妥,这指针实在是太强大了,程序员可以把它指向任何地方,我知道有些地方是操作系统老大的独有区域,是严禁外界进入的,万一指针指到这里会发生什么事?
阿甘说:“这不用你操心,如果有个程序通过指针想访问它根本没有权限的区域,老大就会引发一个segment fault,把这个程序杀死!”
“杀死以后呢?”
“那个程序的内存空间就会被释放, 与此同时老大会生成一个叫做core dump的文件,让程序员们去分析。 唉,今天你真是烦人,问了这么多问题。 不说了,主人要关机了,明天再见!”
风扇停转,电流消失,整个世界安静了。
第二天
我从无边无尽的黑暗中慢慢醒来,迷迷糊糊,茫然四顾。
耳边传来了风扇卖力干活的嗡嗡声,估计就是他把我吵醒的。 这时候CPU阿甘现身了:“兄弟,快醒醒,开机了,要干活了,我要把程序和数据从硬盘读取到你这里来了!”
.....
【本文为51CTO专栏作者“刘欣”的原创稿件,转载请通过作者微信公众号coderising获取授权】