第21章 还在继续!
  里奇后退两步,靠在椅背上,双手交叉在胸前。
  他不是在刁难,他只是充满好奇。
  这个问题不是凭空產生的,而是他真切遇到过的问题。
  所以,里奇也在思考。
  同样地,他也期待眼前这个年轻人,能给出一个让他感到新奇的解法。
  就像他之前做到的那样。
  李林深深吸了一口气。
  此刻他脑海中有混乱、有震惊,但唯独没有恐惧。
  因为他並没有从里奇身上感受到恶意。
  这只是一个挑战。
  一个他必须接受的挑战。
  这就是c语言之父的威能吗,连繫统这种產物都得被他压制。
  幸好,李林的知识都装在脑子里。
  “呼——”
  他没有急著动手,而是先试著理顺思路,说出了自己的思考,
  “要真正解决问题,必须依靠系统本身防御错误的能力。毕竟,错误就像现实世界的熵增,一定会发生。所以,逻辑不仅要正確,还要设置防线。”
  “那就让分配器自己处理。”
  里奇的声音从虚空中传来,他的思路逐渐与李林重合,
  “唯一的目標是,不许崩溃。”
  李林点点头,似乎是同意了里奇的说法。
  他重新抬起手,尝试在方格纸上构筑新的秩序。
  这一次,他从逻辑入手,为它加上了一道免疫防线。
  他修改了分配器,给每一个內存块的头信息添加了一个状態標记。
  分別代表已分配、空閒、已释放。
  释放一块內存之前,先检查它的状態。
  如果状態已经是“空閒”或“已释放”,说明它已经被释放过了。
  这时候不再执行合併操作,而是直接拒绝第二次释放,记录一条错误信息,然后返回。
  “状態机?”
  里奇的声音再次响起,语气里带著不加掩饰的惊喜。
  他知道,他赌对了。
  “你给每一个內存块赋予了一个有限状態机,从而把释放变成了一次带有前置条件验证的状態转移。”
  李林点了点头,手指却没有停下来。
  因为还不够。
  光靠状態標记还不够,错误可能更隱蔽。
  李林的大脑在飞速运转,模擬著编程场景中可能出现的错误。
  比如,释放了一个不属於任何已分配块的地址呢?
  他又在分配器中加入了一个已分配列表,释放时先在列表中查找目標地址。
  找不到?
  那就是野指针,同样拒绝释放,输出警告。
  “防御性编程……在已经设立防线的情况下,还要用结构化的方式来儘可能保证安全。”
  里奇满意地点点头,看向李林的目光不仅有欣赏,似乎还有些感慨。
  像是在看一个和自己走在同一条路上的后辈。
  “说说看,你是怎么想到这些的?”
  李林愣了一下。
  怎么想到的?
  他思考片刻,摇了摇头,然后如实说道,
  “我的能力还不足以想到这些。我只是……站在巨人的肩膀上而已。”
  里奇没有说话,微微眯起眼睛,等待著他的下文。
  “就像细胞。细胞里有遗传物质,也有处理这些遗传物质的酶。它们被同一个细胞膜包裹在一起,不分离。被释放的內存块也应该带著自己的状態、检查状態的方法和处理错误的方法。它不是一个被动的数据单元,而是一个主动的、对自己负责的结构。”
  里奇沉默了很久。
  头顶的日光灯管依旧嗡鸣,身侧pdp-11的机箱风扇依旧呼呼地转著,但他却觉得世界如此安静。
  然后,他笑了。
  “细胞。”
  他缓缓地念叨了一遍,
  “数据和操作数据的函数,封装在同一个结构体里。让结构体自己去处理自己的生命周期。”
  他顿了顿,目光落在李林身上,
  “你来自哪里,孩子?”
  “半个世纪之后,里奇先生。”
  “哦——那真的是……很幸运的事情。”
  里奇语气出奇的平和,
  “你能见到这么多我不知道、也没机会知道的事情。”
  他站起来,走到方格纸前,伸手在那棵已经恢復秩序的二叉树上轻轻一点。
  “这个想法,它应该有个名字。”
  “面向对象,先生。您的c语言,是面向过程的。”
  里奇沉默了一会儿,才缓缓开口,
  “真是精闢的总结。”
  里奇说完后,便仰头注视著面前的方格纸。
  年仅三十岁的里奇,此刻目光却是如此深邃。
  似乎在思考,又似乎只是纯粹的观赏这近乎完美的秩序。
  良久,他才回到桌前,拿起那本一直摊开的笔记本,在上面缓缓写下了几行字,然后把那一页折了个角。
  “拿著吧,孩子,这算是我送给你的回礼。”
  李林接过笔记本。
  来没来得及说些什么,眼前的一切就都开始碎裂、一寸一寸地崩塌。
  【考验异常拋出,强制结束。】
  似乎是察觉到了李林无奈的表情,里奇佇立在碎裂世界的中央,冲他挥了挥手。
  他笑得很开心。
  李林听不到他的声音,但仅从口型,隱约能看到……
  “keep it simple。”
  隨后,白光一闪。
  【考验通过。】
  【“c语言”水平提升(通晓→贯通)】
  【获得物品:“里奇的隨笔”。】
  【解析中……经后人整理,丹尼斯·里奇在开发c语言与unix期间隨手记录的工作笔记。前半部分是內存分配器的设计草图,后半部分是里奇与一位“不知名的访客”关於“面向对象”的对话记录。末尾有里奇手写的一行字:“也许现在还没有人能完全理解这个想法。但总有一天,会有人需要的。”】
  【获得被动效果:“保持简单”——当面对复杂不可解问题时,你的思维会自动將其拆解为有限可解问题的组合。】
  李林猛然回过神。
  他这才意识到,他依旧在胡云程的办公室里。
  但窗外的天色已经暗了下来。
  李林低头看了一眼自己的双手,又看了一眼面前堆积的书本。
  “……”
  “喂!”
  突然,胡云程的手在他面前摆了摆,
  “睡著了,臭小子?!”
  李林有些茫然地抬起头,明显还沉浸在刚才和里奇的深入交流之中。
  胡云程看他那副魂不守舍的样子,哼了一声,把手中的手机递了过来。
  “行了,我算是看出来了,你就是个犟种。”
  他的语气还是一贯的不好听,但手中的动作却很乾脆,
  “严老师,人家搞了二十年嵌入式开发,解决你的问题绰绰有余。”
  李林眨眨眼,似乎还没反应过来,但手上已经被塞了个手机,
  “总之,你有什么问题,最好一口气问明白了,问完就给我收心,再有疑问也得等初赛完了之后再折腾。否则——”
  他做了个掐脖子的手势。
  李林把手机拿到耳边,听筒里传来一个温和的中年男声,
  “小同学,你那个问题,老胡跟我说了个大概。你能再复述一遍吗?我很感兴趣。”
  李林下意识地开口,把自己的问题重新说了一遍——
  当使用函数指针实现回调,且需要修改多个不同生命周期和类型的变量时,如何设计接口才能兼顾简洁性、类型安全与內存安全。
  一边说著,李林在考验中梳理过一遍的知识开始隨著问题自然地翻涌、排列。
  “这个嘛……”
  电话那头的严正江听到问题,皱了皱眉头,似乎也陷入了思考。
  但还没等他说些什么,李林自说自话地,便顺著刚才的思路继续往下推,
  “……不对,其实答案已经在问题里了。”
  “……”
  严正江:?
  在……在吗?
  “把数据和函数指针封装在同一个结构体里,让结构体自己去管理生命周期。接口只暴露必要的函数指针,生命周期由拥有者负责。类型安全用函数指针的类型签名来保证。至於內存泄漏和悬空指针,在分配器里加哨兵值和已分配列表校验,拦截野指针。”
  “……”
  电话那头沉默了好几秒,
  “来,小同学,你把手机先给胡老师。”
  李林默默把手机递了过去,胡云程接过来就被手机那边的震声嚇了一跳,
  “这人你从哪找来的?!”
  “不是和你说了吗,我学生……”
  “你的意思是,你隨便教出来的学生水平比我还高咯?”
  “不是,我没教他……”
  “你的意思是,不教比我教过的还强?”
  “不是……”
  “彳亍,老胡啊,老胡,就你有好苗子是吧!你给我等著!”
  “別,老严——”
  “嘟嘟嘟……”
  “好啊,你小子——”
  胡云程看了看手机,又看了看李林,面无表情的脸抽了抽,
  “前面装成那样给我下套,合著是就是特地来我面前装逼是吧!”