Skip navigation.

自一个人默默走

从 C 的角度使用 C++,而不是反切入 C——这样会简化很多的问题

Posts tagged with "c++"

C 的杂记

, ,

  • C 函数的参数都是按值传递的,而只能用指针传递来模拟引用;这就非常好,因为你可以非常明确地知道,你传递的参数会不会被改变;
  • extern 的链接方式太棒了!
  • 数组并非指针——虽然这个我很早就知道了,但到处还存在前误解,警醒下自己;
  • Bjarne Stroustrup 曾经说过,C++ 语法中丑陋的部分来自于 C——现在我认为,C++ 丑陋的语法并不是来自 C,而是 C++ 自作主张地扩展的与 C 兼容的语法;同理也适用于 C++/CLI;
  • 有一个非常行之有效的原则——当遭遇某风格的源码时,编写或修改和它一样风格的代码,而不是试图去改变这种风格,否则会带来混乱;

无题

, , , ...

早晨吃饭的时候总结了几个事情:
  • 公司使用的 CXCentaur 框架,几乎和现在市面上使用的 Java VM, .NET Framework 的架构理念是一样的;换句话说,CXCentaur 实现了一个非常快速的虚拟机环境;
  • 原先我一直在考虑从 C/C++ 中调用脚本的方法问题,实际上那个是错误的思路——也就是说 C/C++ 通常做为脚本的下层出现,从理论上并不会去关心脚本中有什么内容;
  • Python 是一种复杂的脚本,因为它要提供的东西太多了;而相比之下,公司内部使用的在 CXCentaur 之上的 LPC 脚本就非常的简洁——但问题在于 LPC 太过于 C 化了,以至于所有的调用都是 procedure call 的封装——不过目前没有发现有什么缺点;

补充:
  • 刚刚想到,从 C/C++ VM 中调用脚本的方法是可能的,VM 不会;主动去关心脚本的内容,但是脚本可以在 VM 中注册方法,让 VM 进行回调;
  • LPC 全部使用全局函数调用,在现在看来不是缺点;相比之下,C 的语法虽然不美观,但是目的非常明确;广泛地使用全局调用,在 C++ 看来是一种名称污染,但是就目前来看,这样的方法也没有产生什么问题;

从设计的角度把握编码

,

今天早晨在看自己前不久写的一个新风格的 c++ 测试代码,突然想:
  • 编码要到什么程度几乎都可以,但是根据需求的不同,没必要为了强大的需求而付出太多的代价;
  • 一个良好的设计可以非常好把握编码要编写到什么强大程度;

我称这种设计为 TOD - TOP - Think-Oriented Design/Development - Think-Oriented Programming。

eed

, , , ...

就暂时叫做 eed 吧,晚上写了一些基本的构架,发现了一些问题,阶段总结下:
  • 基于思想进行设计,尽量不依赖于某一特性,例如 c++ namespace;
  • 当一个想法并不容易实现时,换一个角度也许会更容易;
  • 一个合理的系统应该由思想而来;重构的大部分精力也要花费在思想上,而不是代码的某个细节上;
  • 一个没有思想基础的软件工程,每次更新都是只是在“堆代码”;
  • 所有“未将来扩展性”的考虑是,把现在所有必需满足的、和可以预见的需求全部写出来,然后做一个有十足“凭据”的预见性设计;
  • 对于各种可供选择的想法,列举出它们所有的优缺点,然后进行比较选择;如果不能做出一个很好的选择的话,不妨两个都实现,用 policy-based 的方法结合,或者说干脆就换一个思路;
  • 在整个设计完成之前,不要做任何的优化考虑——除非有非常严重的瓶颈问题;
  • 总之,不要影响主线设计的行进;
  • ooa/d/p, tod/p 的设计方法中,几乎都采用了 edd 来处理各种复杂逻辑,因此在思考的时候大量地向着 edd 的方向行进。

就先这么多吧。设想的东西很多,但是基本的功能才是最重要的,因此在整个设计中,界面和代码逻辑不是耦合的——至少在我看来 emeditor 虽然好,但是它的很多东西是粘在编辑器上的。

C 和脚本

, , , ...

我对脚本语言的执行速度近乎绝望。

是的,也许你会说我的机器不够快,也许我的配置有问题——我的理由是这样的,当我使用一个脚本编辑的 editor 时,会发现,比起我使用 emeditor 要慢多了——再快的机器上跑脚本 editor,emeditor 会跑得更快。

pythonwin, spe, eclipse, ... 感觉上到底不是反应迟钝,就是界面不好看、不工整;感觉脚本写成的 editor 在界面统一方面做得不好。emeditor 本身是用 c++ 写的,所以它非常的高效、稳定。

也许我可以考虑使用 c++ 来编写我的代码,但是我已经被 c++ 的复杂性所难倒了。c++ 使用非常华丽、非常安全的代码风格来编写和 c 近乎是相同功能、但是不安全的代码。但是记得以前有人说过,程序员是要对代码安全负责的——也就是说也许你在 c++ 中申请一个指针,可以由智能指针的方法来释放,但那绝不是好习惯——因为你要对自己的代码负责。

C++ 的复杂性

, , , ...

昨天和一个同事聊天,谈到 c++ exception,今天上网找了些资料,回想了一下——没错了,c++ exception 除了给程序本身带来过多的复杂性,并没有对错误处理非常大的贡献。

怎么会提到这个问题呢——首先,当一个 c++ exception 被 throw 时,一般情况下要临时构造一个 exception class,那么分配在 try 栈内的变量/类实例,拥有一些在 destructor 释放资源的惯用法(例如 smart_ptr),对于没有经验的程序员,并不能准确地知道其里面做了些什么事情;且 c++ 标准中没有 finally 的关键字,很多额外的资源要怎样才能保证释放呢?

总之有很多很多的概念,我可以说 c++ 是现在市面上使用的最复杂的程序语言(我不知道要不要加上“之一”),当然 c 语言做很多类似 c++ 的工作的话有很大的代价,所以我要先阅读些 c 代码,然后考虑是否从 c++ 转移到 c。

洗澡时的思考

, , , ...

或许是身上没洗澡之前往往残留着一些影响思维的脏东西吧,每次洗澡时,我的思维都特别清晰。

好了,言归正传,我洗澡时想通了这么几个东西:
保持 c 的简洁性而去使用 c++;言下之意就是在使用 c 的前提下引入 c++ 扩展;
尽量避免使用 c++ 中的那些令人摸不清头脑的复杂的技巧;除非意义十分地被表达,否则不使用 operator overload or implicit conversion;正如很多文献说的,implicit conversion 是 c/c++ 中最糟糕的特性;
优先使用 oo 的方法来编写代码;使用 oo 可以让很多问题简单化(至少对于现在我的知识来说);
对 c++ 类方法,优先使用 virtual 修饰,就像 java 一样,方法默认是 virtual 的,只有一部分才声明为 final;
进行 edd 的方法大部分是 virtual 的,换个角度说 edd 本身就是通过 method pointer 来实现的,假设不使用 virtual 继承 event handler 的话,是很难实现 edd-oo-model;
性能的东西在现在看来不是非常重要的问题了;
把开发的重点转移到 python 上,而不再非常深入地研究 c++;python 能做很多的事情;仅在很少的地方才会用到 c++,所以现在只维护 c++ 的知识,而把开发重点放在 python-oop 上;
当我们需要获得一个消息时,edd 的方法中不是去主动地获得,而是通过 subscibe 来获得 callback,这样可能在执行的效率上要做出点牺牲,但在灵活性上、和易于理解的程度上有很大的提高。

商业产品和 Open Source

, , , ...

刚刚随意地在网上翻看 borland.com,忽然想到一个事情:商业 ide 的整合性非常好,而 open source 的东西,很难有一个完整的产品——虽然有很多人把此当作民主、自由,因为可以任意地搭配自己需要的东西,但问题是,当需要一个马上能用来做一系列事情的东西,你还有心情去搭配吗?

说这个例子的原因是,我在看 bcb 的产品线,想:既然 c++ gui 的设计比较困难,那么为什么不能有一些像 bcb 那样搭配好的产品呢?绝大部分 open source c++ ide 的 gui 往往都没有一个比较统一的标准,或有着各种参差不齐的特点,例如:kdevelop 只能运行在 kde 上,anjuta 也只能运行在 gnome 上;code::blocks 虽然可以跨平台,但非常不幸的是它至今没有 release,商业产品根本不敢用它来开发,当然也有很多人不喜欢 wxwidgets 那样的保守风格。

这里要提到 java 是一个特例,java 的 ide 几乎都有完整的 gui, debug, refact, ... 功能,这和 java 本身有一定的专治色彩是分不开的。

我现在想寻找一个完整的,用于 python 开发的 ide,无论从 gui, debug, refact, ... 到完整的解释等等都有的成品——我不想花费自己太多的精力去考虑从 vim, emacs 等“强大”的编辑器中去组合一个 ide 了。

在 C 和 C++ 中做出选择

, , , ...

我没有想到,在实际的工作中,oo 方法是这么的实用——虽然我曾经支持 gp 而反对 oo,但是现在发现,在实际的代码组织中,oo 方法是十分有效的 ——这也可以很好地解释,为什么 borland, ibm, microsoft, ... 大部分厂商都站在 oo 的立场上。

于是开发 c,可以使用 glib/gobject 来实现 c 语言的 oo;使用 gobject 带来的复杂性,和直接使用 c++ 并没有太多的改善。

关于 c oop 的理由,ibm developerworks 里面的文章是这么说的:

这里我们不讨论每种可能的解释,而只解释为什么拥有一个用于 C 的对象系统是有意义的。其一,比起 C++,有许多开发人员更喜欢用 C。另外,由于项目或平台的限制,可能不会选择使用 C++ 编译器。无论是什么原因,拥有了用于 C 的对象系统,可以使更多的潜在开发人员也进行 OOP 编程(尤其是 GNOME 编程),我们对此表示感谢。(原文)



这些对于我来说不是十分充分的使用 c 取代 c++ 的理由,对于我来说,还要权衡这两种语言。又是一个痛苦的抉择。

Templates 与 C 的思考

, , , ...

templates 实在是 c++ 中最优秀的思想了,不,应该说 templates 是程序设计中产生的最优美的思想了。

于是就有人想把 c 中安插上 templates,于是就诞生了用 c++ 编译器来编译 c 代码的方法,也产生了 gp。实际在我理解中,扣除 class 等一些特性的话,gp 就是 c 的 pb + templates。

早晨上了 cto 的一堂课,感触颇深——用过程式的语言来实现各种 oop 的设计技法——这也可以理解为什么公司里不过多地使用 c++ boost library 等 template features。

想起我在 n 年前去面试时,我跟一个公司的 cto 说:“用 c 可以实现几乎所有 c++ 的事情”——最后被骂了一顿——现在的 cto 告诉我:“这完全是可行的”。

话题回到 templates 的问题上。cto 早晨说过:“lpc 中的 mixed 类型是非常优秀的,相比之下,c 就没有完善的实现”。所谓的 mixed 就是一种可以放置下所有类型的类型,在 c 中的 void * 我不知道有些什么样的副作用,等春节期间好好地研究下 c。

关于 C 的一些想法

, , , ...

早晨到公司,想:如果在 c 中引入 c++ template 机制,那该有多好。

回头又一想,c++ template 是不可能加入 c 中的。template 是 c++ 中最复杂的机制之一,c 引入 template 无非就是给自己增加复杂性,因此加入的可能性非常小。

但是 c 中最好有一个 variant 类型,也就是声明可以到编译时才确定下的变量,gp 一直在宣扬的泛型,差不多在 c 中提供一种灵活的类型就基本能实现了——是的,我说基本,c++ 中的 virtual, namespace, ... 没必要移植到 c 中——而 gp 不仅仅是因为 template 还因为了其它的这些元素。

不知道 c 有没有一个新的标准,或者说它已经有了一种泛型的机制了呢?要过年了,非常忙,春节的那些天正好来研究下 c。

The Selection of Programming-Paradigm

, , , ...

我现在居然为了自己该使用哪种 programming paradigm 而犯愁。

只能说我选择的两大语言都具有 multi-paradigm programming 的特点,所以在选择上,还是有问题的:“太多的选择往往不是好事”。

有时候回想起来 java 的专治性也有一些好处,例如它强制 programmer 使用 oop;强制使用 camel 来为类方法命名等等;强制默认的成员方法为 virtual;强制语言中的所有东西都是 object……

而我现在使用的 c++ 和 python 就没有那么强烈的限制:在我的学生时代,这些看起来是非常民主的措施,但在工作的时候,这种民主则变成一个非常糟糕的选择题。java 的纯 oo 思想,可以让我们集中精力在用 oop 来解决问题上,然后使用其它的诸如 gp 等方法来改进代码的设计;而 c++ 则在一开始就要我们做出一个选择——是优先使用 oop 来解决问题呢,还是使用 gp。

JavaScript 祭

, , , ...

可以说我是一个懒人,比如说我曾经学过 js 所以就希望用它来做更多的事情。

因为之前的 js 非常简单,所以我想用它嵌入更多的程序中进行开发。

然而这种想法在今天晚上,我对 js 的发展失去了信心,之前,在看了 m$ 的 jscript.net 手册应该就有想法了,但以为是 m$ 又一独断的做法,今天晚上却发现,ecmascript 4 的标准,由 adobe, m$, yahoo 等多家公司共同制订。

最让我失望的地方在于 es4 是强类型语言,而且语法非常严谨,有 java 的风格。但很多人需要的是一个强大的脚本,而不是一个复杂的语言。mozilla 声称 es4 的 tamarin vm 会比以往的所有 js vm 都快,但可以肯定的是,性能并不是大多数用 js 编码的人最需要的。

js 需要自己的标准库,需要自己的 byte-compiler,需要自己的简洁——但并不需要复杂。

当然了,es4 也可以像 vb 一样,仅使用 variant 类型。我们暂且把 es4 的类型问题放到一边,另一方面,它引入了太多的关键字、表达式之前的东西,更强大地支持了 html, xml 等 web 创作,但很明显地——它更复杂了。也许你说我懒得接受新的事物,也许它们可以带来好处——是的,我可以回答你,在过去写 js 的过程中,曾经碰到一些问题,但是以为的 js 代码仍然工作得很好——我不需要那些新添加的功能来做更细的工作——我仅把 js 当作一种脚本,当 js 力所不能及时,我会考虑用 c++ 等更复杂的语言对其进行扩充。

当然,我不希望这个文章会引来 es4 fans 的批判,纯属个人观点,在 es4 那么复杂的情况下,也许我会更倾向于使用 python。

关于编辑器

, , , ...

绕了一圈,又回来了,非常讽刺的是,我把学习 Emacs 的经验,用在重新审视 Vim 上。

在选择一个良好的编辑器时,我主要看重这几个方面:
1. 良好的文字编辑:当然,这是编辑器最基本的,也非常必要的;
2. 有强大的搜索能力:我使用过 EmEditor 其依赖的 regex++ 所具备的搜索、替换、全文搜索、批量替换、正则等等的支持,是我使用过的在这方面最强大的编辑器;然而 EmEditor 在代码补全文件排版等等方面也有不足,因此,使用其它的编辑器也是要考虑的问题;我本来没有找到 Vim 的文件搜索功能,就在我卸载掉 Vim 的时候,却阴差阳错地找到一个 Vim 的用户组——了可以使用 vimgrep 进行文件搜索;
3. 有非常强大的自定义能力:在这点上,我非常欣赏 Vim 和 Emacs,它们提供了非常强大的脚本语言,几乎可以做任意的修改;
4. 灵活的扩展性:我试用了 SciTE,但这最终造成了我不得不放弃使用它——其基于 C++ 编码的,不支持脚本进行动态扩展,每做一个改动都要修改 C++ 源码,然后重新 make;
5. 编译、调试支持:SciTE 虽然可以很好地捕捉到编译器的错误输出,但我不知道如何更改其编译参数、也不知道如何将其结合 GDB 进行调试;其虽然可以调用 python 解释器,但是我不知道如何结合 PDB 进行调试;在这个方面上支持的提供集成支持的只有 Vim, Emacs 和 Visual Studio;
6. 最好是免费的:上面提到的 Visual Studio 就被排除在外了,我不想让自己的开发事业建立在某种要钱的产品上,所以只能使用 Vim, Emacs, SciTE 等等;
7. 功能细腻:这点我本来不是非常在意的,但是用了 Emacs,发现其很多的功能相对于 Vim 来说比较粗糙——比如说显示行号,一个非常简单的功能,但是 Emacs 居然要使用插件来实现,并且使用的时候有诸多的限制——也许是我对 Emacs 的了解还不够吧;

LOD

, , , ...

LOD?! 不要惊讶,是 Language-Oriented Development 的缩写,什么意思,就是
在开发一个系统之前,先写一种专门用于该系统的编码语言。

元旦放假前,听同事在谈论这个话题,刚刚洗澡的时候想到,自己总结了下:事
实上,不是要开发一种适合于系统的语言,这是相当耗时的做法,我们现在需要
的是一个面向系统本身的库;而 LOD 所强调的开发一种语言,实际上是在强调脚
本语言在系统开发中的作用。

根据 LOD 的思想,实际上很多事情在我们现在的开发工作中也是在不断进行的:
例如要开发一个系统,我们往往会先开发一个相应的库;但通常做法是:用 C++
开发一个系统的话,我们会使用 C++ 先开发一个库,然后用库和 C++ 组合一个
系统。LOD 的思想中强调了脚本语言在开发中的重要作用。

乱说了一堆,现在总结:LOD 我觉得应该叫做 DOD - Domain-Oriented
Development - 面向领域的开发。具体做法是,开发一个面向领域的库,可以由
C++ 或者任何合适的语言来开发,然后暴露给一种脚本,比如用 boost:: python
暴露给我非常推荐的 Python,然后使用该脚本语言进行系统的组合。使用脚本来
完成后期工作的优点是,其非常地灵活,甚至可以在动态更改它的一些配置。

跨语言开发

, , , ...

回想起两年前,我还在思考使用单纯的 c++ 进行开发工作的事情,现在想起来都
觉得好笑。

今天下午在书店看书,看到有些脚本语言的——在前一个公司——他们使用 mfc 开发
界面——由此而引发我开始思考使用脚本来编写 GUI 的路看来是正确的。

现在的公司中,我从事着用 cegui 开发 game gui 的任务,在现在看来,界面与
逻辑分离的实现也是合理的——在某种程度上 vcl 比 mfc 方便,但很少有公司把
vcl 用在商业开发上。

于是现在的开发思想非常简单:用 python 做几乎所有的事情;在 python 力所
不能及的时候,才使用 c++ 开发底层扩展供 python 调用。

把接口暴露给脚本

, , , ...

昨天快下班的时候在和同事谈论“把一个库,例如 sqlite c api 让 lpc 从中调
用”的问题,同事给了一个完整的方案,事后在回家的路上回想,发现其方法非常
繁琐。

晚上回家把问题总结了一下,其实是“把某某库的 api interface 暴露给某种
script vm”的问题。在 lpc 中,实现该过程的行为非常繁琐,而 python 通过
boost:: python 库,是非常简单的,而且 boost:: python 还可以把 python 类
暴露给 c++;今天陪老娘去逛街,回到家开门的一瞬间想到,managed c++ 把其
它非 managed code 暴露给 .net framework 的最好工具,当然,也是把 .net
framework 类、方法等暴露给 unmanaged 的最好工具——同样是双向的。

结论是,有 vm 的 script 一般都存在把非 vm 接口暴露给 vm,或者把 vm 中的
元素接口暴露给非 vm 的方法;script 是一种可以非常方便地组合 system
language (如 c/c++, ada) 等的最好工具;Stroustrup 所说的优先开发库的做
法不适合于 script language。

KISS?更进一步,我们要 KIISS!

, , , ...

原本这个是要写入我的一个《》手册,但是公司对代码控制很严格,我也懒得把文档拷贝来拷贝去的,所以就先写在这里了。

KISS - Keep It Simple, Stupid.
相信很多人都知道,特别是程序员,但是我现在要讲的不仅仅停留在 KISS 上。
在实际的编码中,我发现了 KIISS 的重要性——
KIISS - Keep Its Interface Simple, Stupid.
这里不仅仅是强调简单,而是要强调被暴露的接口简单。我原来觉得如果 C++ template 不能实现接口文件和实现文件分离的话,那还不如所有的成员方法都写成隐式 inline 的形式——但结果证明,那种写法中接口和实现混合,非常混乱。
于是我就开始探讨一种极其简化接口的方法,最终的总结还在不断进行中,但是有一些已经在实际编码中使用的方法,如:使用 pImpl;使用 GP Interface 方法等等。

当然这只是初稿,还要整理。

为什么我要与众不同?

, , ,

是的,我一直在问自己这个问题。
今天早晨写一个文章的开篇,我也这么问自己——在大家都使用 OOP 编程的时候我使用 GP;在大家认为的一些公理前,我发展自己实践(比如在有些设计上,我站在与 STL 的对立上)……老娘经常说,发现我喜欢与众不同。
很多人误解道:我的存在是为了证明与众不同的道路仍然会成功——一段时间我自己也这么认为——但是很快就被自己推翻了——与众不同不是因为我刻意要“与众不同”,在实践中,我发现了现实中执行的“公理”存在着许多问题,而试图去修正这些问题,就造成了与众不同的现象。
以前有个朋友和我说,什么赚钱就往什么发展。很不幸,我没有听进去——虽然有思考过这个问题,但是现实中,我不能容忍自己被金钱而迷惑了设计。比如很多 C++ 大师们喜欢的 .NET Framework 我就不喜欢,因为我不喜欢它代码的组织方式——就 GP 需要使用 OOP 的方式来组织代码,我还没有一个完全的概念。

My Own Script

, , , ...

前些天自己在思考设计一种 GP 脚本的问题,还有昨天在网上看 D Programming Languare 和 DMDScript 的资料,昨天晚上睡觉前突然有所感触,今天早晨上班赶快笔记下来。
首先,我认为前些天的那些想法是错误的。因为创造一种自己的语言,代价不只是写的成本高,在与他人交流、融合别的设计等等方面也是比较困难的;
第二,D 和 DMDScript 试图创造一个完全属于其自己的世界——可能在其设计者眼中,D 和 DMDScript 语言本身是完美的,其组合也是完美的——但有一个事实不得不看到——D 的应用面非常狭窄,换句话说,几乎没有企业把 D 用在直接的项目开发;
最后,说一点自己的打算:我不准备创造一种自己的脚本语言(它本来叫做 CZS - Concept Z Script);也不准备去学 D 或 DMDScript;也许会去学一种与 C++ 结合非常好的脚本语言,也许会做些修改;但是有一个原则——去接受融合别人的设计,而不是试图去创造一个世界。