转:c的回归-云风

C 的回归

周末出差,去另一个城市给公司的一个项目解决点问题。回程去机场的路上,我用手机上 google reader 打发时间。第一眼就看到孟岩大大新的一篇:Linux之父话糙理不糙 。主题是 C 与 C++ 的语言之争。转到刘江的 blog 下读完了Linux之父炮轰C++:糟糕程序员的垃圾语言 大呼过瘾。立刻把链接短信发给了几个朋友。

语言之争永远是火药味十足的话题。尤其是 C 和 C++ 的目标市场又有很高的重合性,C++ 程序员往往对C++ 其有着宗教般的虔诚。我想,今天我在自己的 blog 上继续这个战争,一定会换来更多的骂名。只不过这次 Linus 几句话真是说到我心坎里去了,不喊出来会憋坏的 :D

首先,给不熟悉我的朋友做一个技术背景的自我介绍:

我不是一个 Linux 的 fans ,虽然我今天对 Windows 也没有什么好感,但我的大部分工作还是在 WIndows 上做应用软件开发的,对 Windows 还算熟悉。现在我也用非 Windows 的系统,但那是一台 FreeBSD 的机器,不是 Linux 。

我自认为对 C++ 相当熟悉,精读过市面上能买到的关于 C++ 的大部分书籍,像 D&E of C++ 这样的经典还读了不只一遍。用 C++ 写过至少数十万行代码,阅读过 STL 的大部分源码,和 ACE / Boost 的一小部分。

曾经我是 C++ 的忠实粉丝,如果谁说 C++ 的不是,要么会选择跟他辩论到底,要么会对此人不屑一顾。

还有一点我认为非常重要:我第一次爱上 C++ 是 15 年前(1992 年),然后对其慢慢冷淡,回归 C 的怀抱。而到了 2000 年,我又一次爱上 C++ 。也就是说,从热爱 C++ 到否定它,在我的个人经历中,有过两次。不排除未来有第三次的可能,但这一点足可说明,否定 C++ 是出于一种理性的判断,而不是一种冲动。

写上这些,并非是想倚老卖老。我知道,想骂我的 C++ 程序员,更讨厌有人倚老卖老的数落 C++ 的不是。而且论资格,我顶多及的上 Linus 大大的一个零头,既然有老人在前撑腰,下面说话的底气就可以足一些了 :)



C 是 C++ 的一个子集(从 C99 开始已经不是了),用 C 能写出来的代码,C++ 一样可以写出来,然后可以完成的更好。

这是新手们自以为是的攻击武器。Linus 用了一个很恰当的理由做出反击:“你当然可以用任何语言编写糟糕的代码。但是,有些语言,尤其是带有一些心智(mental)包袱的语言本身就非常糟糕。”

没错,我最想说的就是这个。C++ 就是一个“带有一些心智(mental)包袱的语言”。这对软件设计的影响非常之大,没有经年的软件开发实践很难理解这一点。

从这一点上展开,把 ASM 和 C 比较的问题和 C 与 C++ 的比较相提并论就没有意义了。

接下来要找到的问题要点就是,C++ 比 C 多出来那些东西后,真的会带来心智包袱吗?这个问题不好回答。单纯从 C++ 语言特性的繁杂导致的不易掌握和误用这些角度是很难说服我自己的,更别说去说服那些比我聪明的多,刻苦的多的 C++ 程序员们。我自认为对所谓 C++ 的高级特性掌握的还是不错的,并运用在诸多实际项目中。他们相当有趣,在某种程度上也非常的有效。代码可以获得相当高的执行效率,并可以缩短编码的时间(更少的键击数),完成他们也有很大的成就感。

好了,让我再引用 Linus 的一句说到我心坎里的话。“字符串/内存管理根本无关紧要。这不是重要的部分,而且也不复杂。唯一真正重要的部分是设计。”

设计!这才是重中之重。

如果要说,这最近 10 年的程序员生涯我学会了什么?我认为,我比以前能设计出更好的代码了。能更准确的把握设计的坏味道。而对编程语言的掌握,对操作系统的熟悉,工作相关知识的了解等等。那些只是自然而然发生的事,那些是知识的积累,而非能力的提高。

“抽象”,“面向对象”,“设计模式”,这些重要吗?重要。对软件开发相当重要。但重要不是必要,执迷于“抽象”会使你离目标越来越远。当我们一次又一次的提取出事物的共性,建立起抽象层的时候,我们可能丢弃了真实。C++ 继承了 C 语言中“信任程序员”这一设计哲学,致力于让程序员在建立抽象层时,可以不做出额外的消耗。他的解决方式是提供尽可能多的语言工具和设计选择,任何一个都允许你在不用的时候不带来额外的性能损失。

这是一个美好的愿景:C++ 程序员指望可以建立强大的可复用的抽象层,面对世界上一切的具体应用。同时 CPU 执行序列在穿越这个坚厚的抽象层的过程中,居然可以以光速通过(通过抽象层没有额外的执行效率付出)。为此:C++ 社区创造了 STL ,创造了 Boost 。它们共同的关键词是:效率、复用。

再往上呢?另一个问题产生了:“——低效的抽象编程模型,可能在两年之后你会注意到有些抽象效果不怎么样,但是所有代码已经依赖于围绕它设计的‘漂亮’对象模型了,如果不重写应用程序,就无法改正。”这一段依旧是 Linus 语,我不停的引用,是因为我明白这一点,但是不能表达的更清楚。

使用 C++ 的程序员不断的强调复用性,却不断的需要重写代码。如果一段代码可以不被重写,那多半是因为对重写工程量的妥协。是的,其实我们可以用 C++ 的各种特性写出更好,更漂亮,更高效的代码。两年前的框架不那么完美,不是 C++ 语言的错,是两年前的我能力有限的缘故。但是因为需要改写的是设计框架,这意味着我们必须跟着变更已经完成的功能模块,或是加上桥接层。

的确,STL 和 Boost 都是世界顶尖程序员完成的。代码质量非常的高(当然,我对 Boost 的一部分持保留意见)。我不拿编译器兼容性和可移植性或是编译速度说事,虽然这些的确是现实问题,但不足以成为反对 C++ 基础类库的理由。

好好的用好 C++ 当然得用好 STL ,Boost 也应该认真考察一下。能够仔细读一下源码更好。合格的 C++ 程序员应该做这个。否则作为 C++ 程序员你就违背了 C++ 语言的设计哲学:C++ 信任了你,你就该对的起这种信任,搞清楚你写的每一行代码背后,机器都去干了什么。

但是,STL 过于庞大了,Boost 更加是。我不是抱怨阅读和学习它们的源码的难度和需要的时间和精力。正相反,我在学习它们的过程中充满了乐趣和感激之情。高手前辈透过这些高质量的代码教会了我很多东西。我隐隐担心的是,这么庞大的代码,它的设计不可能是永远正确的。两年之后,他们的设计肯定依旧正确,再两年还是的。但是我几乎敢肯定,放之更长远的时间来看,绝对会在某些设计领域发现其不是最佳的选择。到那一天,我们会选择修改吗?我想 C++ 社区会被迫选择妥协。但是,C++ 程序员心中会充满痛苦。

C 在这个问题上的抉择是不一样的。在效率问题上,C 程序里最令人担心的是函数调用的消耗。C++ 程序员最津津乐道的案例就是 std::sort 全面击败了 C 库中的 qsort 。C 语言的失败正在于多余的函数调用消耗。

但是,从一开始 C 就选择了承认函数调用的消耗,而这一点几乎是唯一。付出了这个代价后,设计失误导致的效率下降问题几乎总可以避免。C 和 C++ 都可以选择重写设计失败的部分,但不一样的是, C 程序员几乎可以不考虑妥协的问题。同样的是考虑极端效率的语言,C 语言坦然面对缺陷,才是真正的符合了 KISS 原则。

我对这个问题的见解,可以再引用 Linus 的一段话作为收场。“如果你想用更花哨的语言,C++绝对是最糟糕的选择。如果想要真正的高级特性,那就选择有垃圾回收或者好的系统集成的,而不是既缺乏C的简约(sparseness)又缺乏C的直接而且没有重要概念的高层绑定(high-level bindings to important concepts)的东西。”。这是我最近几年来一直坚持的观点:C++ 的发展,一定要补充对 GC 支持所需要的特性

强调一下,我并不讨厌 C++ :) 。 C++ 的粉丝们可以随便骂我,但是不要带上阶级仇恨。



ps. 最近两年多,我在做一个游戏引擎的项目。这个项目现在是第三个版本了。第一个版本是用 C++ 实现的,但是没有用任何已存在的类库(包括 STL)。在第二个版本中,我去掉了所有使用 C++ 高级特性实现的部分,只使用了 C++ 基本特性实现所有。今年重写的第三个版本,全部换成 C 代码了。这个项目的发展,可以反应出我个人对 C/C++ 理解的心路过程。

时间: 2024-10-25 14:21:46

转:c的回归-云风的相关文章

cocos2d-x 3.1 集成 云风pbc

cocos2d-x 3.x版本变动比较大,从改用cmake管理整个项目,到使用python集成一体化的项目工具.这些都是我喜欢的,我可以很容易的在我的ubuntu上面搭建环境,而且根本就不用考虑IDE的事情,sublime-text or emacs足矣.唯一需要自己动手的就是制作一个比较好的调试工具.我是使用lua+cplusplus开发,所以调试就比较的难受,暂时只能这样,后面考虑自己实现一个远程lua调试工具.触控有发布一款IDE,可是目前没有linux平台的版本,我想以后也不会做的,所以

四个月的隐居和一个新的开源项目——云风典藏

    縱有千年鐵門檻 終須一個土饅頭 ——宋·范成大 这么长时间没有来博客园了,上一次发博客到现在,整整四个月了,这期间发生了很多事情.  今年七月份,也正是我本科毕业的时间.正当别的同学要么读研要工作的时候,我却呆在这儿,练了三个多月的书法.  我一直在想一个问题:大学四年学了关于计算机的这些东西,到底是对是错?  如果脱离了生活的感性,就算是最强大的理性逻辑只会变成最可笑可悲的虚无幻灭.不论好坏,永远都是清者自清,浊者自浊,强者自立,弱者自贱.从古到今,这个世界一直都没有发生过一丝一毫的变

转:云风skynet服务端框架研究

转:  http://forthxu.com/blog/skynet.html skynet是云风编写的服务端底层管理框架,底层由C编写,配套lua作为脚本使用,可换python等其他脚本语言.skynet主要工作是管理注册服务,并开启多线程协调服务之间的调用和通讯. skynet一般用于开发游戏服务端程序. 注意:资料开始往github组织账号skynetclub上转移,本页面不在进行更新主要收集学习skynet有关的任何内容,如果你有好的资料或者你在研究skynet,可以将资料或链接地址发给

云风pbc源码alloc.c

#include <stdlib.h> #include <stdio.h> // 用于统计内存的申请和释放次数匹配 static int _g = 0; void * _pbcM_malloc(size_t sz) { ++ _g; return malloc(sz); } void _pbcM_free(void *p) { if (p) { -- _g; free(p); } } void* _pbcM_realloc(void *p, size_t sz) { return

[转至云风的博客]谈谈陌陌争霸在数据库方面踩过的坑( Redis 篇)

« 谈谈陌陌争霸在数据库方面踩过的坑(芒果篇) | 返回首页 | linode 广告时间 » 谈谈陌陌争霸在数据库方面踩过的坑( Redis 篇) 注:陌陌争霸的数据库部分我没有参与具体设计,只是参与了一些讨论和提出一些意见.在出现问题的时候,也都是由肥龙.晓靖.Aply 同学判断研究解决的.所以我对 Redis 的判断大多也从他们的讨论中听来,加上自己的一些猜测,并没有去仔细阅读 Redis 文档和阅读 Redis 代码.虽然我们最终都解决了问题,但本文中说描述的技术细节还是很有可能与事实相悖

[转至云风的博客]开发笔记 (2) :redis 数据库结构设计

接上回,按照我们一期项目的需求,昨天我简单设计了数据库里的数据格式.数据库采用的是 Redis ,我把它看成一个远端的数据结构保存设备.它提供基本的 Key-Value 储存功能,没有层级表.如果需要两层结构,可以在 Value 里保存一组 Hashes . 这是我第一次实战使用 Redis ,没有什么经验.不过类似的设施几年前自己实现过,区别不大.经过这几年,有了 Redis 这个开源项目,就不需要重造轮子了.但其模式还是比较熟悉的.也就是说,是按我历史经验来使用 Redis . 一期项目需要

C 封装一个通用链表 和 一个简单字符串开发库

引言 这里需要分享的是一个 简单字符串库和 链表的基库,代码也许用到特定技巧.有时候回想一下, 如果我读书的时候有人告诉我这些关于C开发的积淀, 那么会走的多直啊.刚参加工作的时候做桌面开发, 服务是C++写,界面是C#写.那时候刚进去评级我是中级,因为他问我关于系统锁和信号量都答出来.开发一段 时间,写C#也写的很溜.后面招我那个人让我转行就写C++和php,那时候就开始学习C++有关知识. 后面去四川工作了,开发安卓,用eclipse + java语法 + android jdk,开发前端,

转载--C++的反思

转载自http://blog.csdn.net/yapian8/article/details/46983319 最近两年 C++又有很多人出来追捧,并且追捧者充满了各种优越感,似乎不写 C++你就一辈子是低端程序员了,面对这种现象,要不要出来适时的黑一下 C++呢?呵呵呵. 咱们要有点娱乐精神,关于 C++的笑话数都数不清: 笑话:C++是一门不吉祥的语言,据说波音公司之前用ADA为飞机硬件编程,一直用的好好的,后来招聘了一伙大学生,学生们说我靠还在用这么落后的语言,然后换成C++重构后飞机就

Unreal发展史

Unreal发展史 引子 四年前的一个深夜,或者说是一个早晨,Unreal的传奇开始了.它发生在马里兰州一个不起眼的市镇Rockvill,在一套公寓大楼里回响起一支墨西哥流浪乐队的曲子,那里住着Epic MegaGames的游戏开发成员. 清晨5点,三位游戏设计师还在听着最后一首曲子,那墨西哥人特有的华美旋律直透墙壁传至外间.毕竟,在游戏世界里,清晨5点,并不是指公鸡打鸣天要亮了,而是意味着程序师们苦熬了一个夜晚后终于可以关灯睡觉了. 作一名游戏开发者从来就不是潮流,而在当时那个年代,它更是没有