杰克-逊の黑豹,恰饭了啦 []( ̄▽ ̄)
keywords: Redis
c
cpp
厌弃c言语的现象
长久以来,程序员们对待c言语的态度十分矛盾,主要应该有这么几种:
- 喜爱、作业中运用c言语;
- 不恶感、作业中运用c言语;
- 不恶感、作业中不运用c言语;
- 恶感、作业中运用c言语;
- 恶感、碰都不碰c言语;
赞赏c言语的程序员,或许会有这些观点:
- 运用c言语的程序员是最nb的;
- 真实的编程大佬都运用c言语;
厌烦c言语的程序员,大抵是因为这些:
- 没有舒服的包办理机制;
- 没有丰厚的规范库;
- 没有面向对象的语料支撑;
- 内存不行安全(内存走漏、悬垂指针、不合法指针、无效指针等等);
- 编译器输出信息不行好;
- 错误处理不行舒服;
- 项目办理杂乱;
再加上,像Rust/Go/Swift等这种现代编程言语的呈现,更让许多程序员厌弃c言语。
现代编程言语和c言语比起来,有什么最大的特色?以我个人而言,最大的特色便是编程言语的表达能力 十分出色,不是C言语能够比拟的。表达能力更具体地讲便是更灵活、更模块化、更适合人阅览。
难道说c言语真的是魔鬼吗?
反驳者一定会举出嵌入式开发、操作系统开发、驱动开发范畴的成功案例。
但我觉得,这样就又大又空洞了。
近来,我在看Redis1.3.6源码,觉得却是个很好的例子说说这事儿,不过读者大可放心,本文不是xx源码阅览
, xx源码细品
的文章,更不是什么八股文,单纯作为一个例子,解释下c言语是不是魔鬼这回事儿。
先说下我个人的定论吧。
c言语是不是魔鬼,取决于你能hold住多少c言语代码量
。hold住,c言语的缺点不是事儿;hold不住,c言语就会带来悲惨剧。一定程度上,这就像咱们尝试三个小时坚持精神高度集中相同,固然你说自己的c言语功夫十分扎实,可是随着项目规模增大,我可不信任你照样能够注意到每个角落的c言语隐患。
假如你是95后,c言语不适合作为你的主力开发言语,可是你能够学习由c言语开发且十分稳定的项目,也能够基于c言语ABI将这些c言语项目植入到其他编程言语开发的项目中,比方Rust/Go/Javascript/Swift项目。
为什么挑选Redis1.3.6
事物总是由简入繁,功用总是由少渐多,项目总是由骨到肉。
越早的版别,越简单看出作者的微观思路。
越新的版别,越会充斥各种新功用、小功用,越发讳饰作者最初的构思。
我从github下载好Redis后,发现最早的一个版别号便是1.3.6, 所以就用这个做参考了。
实际上,我硬着头皮看了两天最新的版别,发现的确啃不动。
看看Redis怎样处理包办理问题的
在1.3.6版别中,redis没有依靠的包,可是在最新版别中,redis将这些依靠放置于deps文件夹下。这里边没有什么特其他地方,便是将依靠的库房源码放置在一个独自的文件夹下,定时去看看库房源码有没有更新,假如更新的话,按需求将本地做更新,就和你的本地库房、长途库房相同。
一起,你也看到了,依靠并不多的确能够这样做,假如依靠多的话,这么搞就难搞了,就需求包办理程序(第三方的或许自己开发的)。不过嘛,一般用c言语开发的项目,都是追求极度功用,功用十分专注的项目,不会掺入太多的依靠。可是应用层项目就不同了,依靠贼多。
看看Redis怎样处理规范库不太丰厚的
c言语开发时用到的API基本上是操作系统原生供给的API,这些API都散布在操作系统供给的固定的.h
文件中,比方:
unistd.h
sys/sysctl.h
pthread.h
sys/stat.h
fcntl.h
execinfo.h
ucontext.h
当然也需求c言语供给的规范库.h
文件,比方:
stdlib.h
stdio.h
stdarg.h
erron.h
ctype.h
例如redis.c
文件中就用到了许多耳熟能详的.h
文件:
两类之外的功用,要么从第三方复制,要么就要自己写。当然,在redis1.3.6中依靠并不多,只需求一些数据结构的完成,比方哈希表(hash table)、动态字符串(dynamic string)、双向链表(double linked list)、压缩型字符串映射表(zip map, 应该是redis作者首创的)。这些都是redis作者完成的。
可不要被完成
吓坏了。
自己创造式地想到一个数据结构,然后用代码写出来,叫做完成;
自己参考数据结构书本、论文中的理论,给出自己的完成,这也叫做完成。
都成年人了,要知道:考试不是只叫做闭卷考试
。
像pqsort(部分快速排序),redis作者便是参考NetBSD平台下的libc源码完成的,作者在代码注释中给出了声明:
你或许会问了,我完成的版别功用无法保证怎样办?redis作者其实也告诉咱们答案了,那便是先搞出一版完成,至于功用好坏是另一个问题,能够先不必管它。所以,在ae.c
的文件中,咱们看到redis作者写到这样的注释:
c项目一般坚持功用专注、功用卓越,常常要定制化一些数据结构的代码,所以即使规范库参加这些数据结构,也未必能满意c项目的需求,或许也派不上多大用场。
如此看来,c项目不太需求那种普适、一致的规范库,更需团队开发、企业开发、安排开发范围内的规范库。
可是关于技能经历尚浅(没查阅论文、手册、其余资料,独立完成一些功用库)的开发者来说,他们需求的是包括功用的规范库,而不是刚提到的那种高度定制化的规范库。
所以规范库不太丰厚的这种问题,关于项目不大、开发者具有经历的情况而言,不成问题;关于经历不足的开发而言,是个头大的问题;关于项目贼大的情况而言,无论经历多少,都是头大的问题。
看看Redis是怎样处理面向对象编程的
面向对象编程,说的便是一种编程思想,但一部分开发者常常会被编程言语的办法所蒙蔽,以为编程言语给出了面向对象代码办法(供给class extends public等关键字),才算面向对象了,关于没有给出这种办法的编程言语,就无法面向对象编程。
看看Redis是怎样做的吧。
struct
等效于class
。aeBeforeSleepProc
便是类中界说的成员办法啊,其界说如下:
至于继承,能够运用组合
的办法代替;
至于多态,能够持续运用函数指针或许改用函数映射表代替;
宽泛地讲,只要有了封装
, 即使没有给出严厉的继承
和多态
, 也能够以为是面向对象
。究竟,面向对象是一种编程思想,不是僵死的格局。
不过呢,言语本身假如供给了面向对象概念的关键字,代码直接了解起来的难度就大大降低,加之有IDE功用的协助,读代码愈加顺利,这是c代码所不及的。这也便是说,当项目的概念变得十分多,c代码即使能够面向对象编程,但也是个问题,会让读代码的人一通找啊找。
Redis怎样处理内存安全问题的
这个问题的确是要害,在这个版别中,redis并没有给出什么十分好的内存安全手段,有的话,也只是在界说数据结构的时候,给出该数据结构的内存开释办法:
和cpp的析构函数一个道理,只不过cpp是编译器刺进内存开释代码,c言语是开发者手动参加。
在代码量hold的住的情况下,开发者的确有满足的精力和耐心保证内存问题,可是代码量一旦上涨,开发者恐怕就顾不过来了。你能够看到像linux这样大型的项目有不少issue,但你很少听说hello-world级其他c代码有什么issue。
所以,到底是人去处理内存问题还是编译器处理内存问题,归根到底便是在大量作业的条件下,你更信任人的体现还是机器的体现。相比之下,我觉得机器更靠谱一些。
c项目很杂乱,无法阅览?
一般而言,在相同老练的情况下,c项目的代码读起来会麻烦一些。但这是老练之后,也便是在参加杂七杂八功用、BUG布丁等等之后的c项目。以Redis 1.3.6为例,其结构适当简练:
主体结构就这么直白,后续版其他杂乱化,都是功用扩展、结构调整,这条主线是不或许断掉的。所以,别把C项目幻想的那么杂乱,那么难。C项目的杂乱还有一种或许是C言语表达能力导致的。因为C言语语法满足简练,直接用的操作系统API,封装比较少,其他言语三言两语交代的工作,C言语或许要多说许多话才能够表述出来,可是编译到了二进制办法的产品,C言语就比其他言语“简练”了。
后话
C言语并没有那么可怕,它不是开发者的定时炸弹,也不是开发者的无双宝剑。C言语到底怎样样,很大程度上要看代码量和开发者的承受能力。并不是说许多项目由C言语编写,就证明C言语是一门你能够信赖并运用的言语,很大程度上讲,许多项目用C言语开发是历史问题,在那个时代和阶段,编程言语的挑选余地太少,哼不能从1980年比及2010年今后,再运用现代化编程言语编写代码吧?
从另一个角度上看,这个时代你完全能够不运用C言语,没必要跟着上古大佬的品尝走。须知,东西是用来解放你的生产力的,不是给你的生产力添堵的。你用不必C言语,和你是不是一个合格的软件工程师,没什么必要的联络。
不过,不必归不必,学习还是要学习的,究竟ABI层面还是以C言语为规范的,想了解函数调用、指令跳转等内容,C言语是避不开的。
关于要不要持续运用C言语,你有什么观点呢,欢迎留言。