作者: admin

  • 如果外星人来了

    刚看完《V星入侵》第一集,感觉还是非常有意思。

    故事的开始非常像《独立日》或者是《第九区》,外星人的飞船降临到了各个大城市上空。

    如果是中国编剧,会如何写一个和谐的故事呢?也许是这样:外星人来到中国土地上,被勤劳善良的中国人民所感动,哭着喊着要加入中国国籍,死活也要住在我们的帝都。弄不好外星帅哥美女还会爱上我们的美女帅哥,下一代混血可以有更多故事讲。最好他们也认毕老爷,上“星光大道”唱个爱国歌曲啥的。

    你把外星人改成外国人就知道了,这就是正在编着演着的故事。

    这里面无论是外星人还是外国人,都是那么的友好帅气可爱,个个都有阳光的笑容、金发碧眼。文化冲突、爱情火花是一定要有的,结局一定要是光明的。

    不过美剧的编剧基本上都是悲观主义者,实际上从威尔斯以后,大多数的科幻作家对于未来的想象都是悲观的(早期中国科幻的代表作《小灵通漫游未来》只能算是儒勒凡尔纳“乐观科幻”的滥觞)。

    在当代中国科幻作家中,我最喜欢刘慈欣,不仅仅是因为他的作品够“硬”,而且也足够理性。

    刘慈欣的代表作《三体》就讲述了一个外星人与地球人的故事,只是他笔下的外星人是为了侵占地球的资源,手里拿着的不是鲜花而是武器。

    其实看看历史就知道了,带有侵略性扩张性的高等级文明与相对原始的文明接触,故事往往都是悲剧性的。比如美洲的印第安人,比如南美的印加文明。当然也有相对落后的文明毁灭高等级文明的,比如蒙古人入侵中原,比如满清入侵中原(我不认为他们是中华民族的一份子,他们只能算是文明的毁灭者),这种特例只出现在高等级文明的扩张性极弱或者低等文明有着超水平的军事力量(而且往往也有超级军事领袖存在)的前提下。

    如果我们与外星人相遇,是应该握手还是举枪呢?有选择的前提是我们的科技水平军事水平可以与外星人匹敌。如果外星人真的来到地球,这基本上标明地球人已经可以认命,期待外星人不喜欢吃地球人的肉,期待他们真的只是为了传播文明(可能性小到没有)。我记得以前看到过一个说法,说外星人既然能来到地球,代表他们的文明要高于地球人,道德水平应该也高于地球人,所以会善待地球人,诸如此类。这个基本上属于一种幻想,假如外星人看地球人就好比地球人看神户肥牛,那么我们就等着被人吃吧。牛有没有智力?牛之间有没有交流?猴子有没有智力?猴子之间有没有交流?应该是有的,但是人一样吃它们,不是么?看看美国人如何对待印第安人,看看澳大利亚如何对待土著人,看看西班牙人、葡萄牙人如何对待土著人,看看英国人如何对待土著人,你应该就知道结局了。

    当然我们可以期待,如果有吃人的外星人,应该也有”地球生物保护“这样外星人的组织,呼吁不要吃这些长着四肢,表情丰富,繁殖力很强,非常破坏环境的生物,因为他们(或者是外星人眼中的“它们”)丰富了地球物种云云。

    OK,总而言之,如果外星人来了,我们到底应该怎么办呢?你们不管,我还是回火星吧。

  • 勿用屠龙来杀猪-论如何正确整合Lua与C++

    经常有人问到关于Lua的问题是“Lua如何能使用C++的成员变量?”“Lua如何调用C++类的成员函数?”“C++的复杂数据结构(如数组)如何传递进入Lua让Lua可以使用?”

    这些问题之频繁,几乎每天都可以看到。问题的起源也很简单,这些提问者大多是C++程序员,公司需要使用Lua,他们就想如何能够“完美无缝”整合C++和Lua。

    如果在谷歌中文(google.cn)搜索Lua关键字,第一页大概前五六个网址中会有云风的这篇文字《Lua 不是 C++》,里面的结论部分十分精彩:

    对于那些新接触 lua 的 C/C++ 程序员来说,我的第一条建议通常是:看看 lisp/scheme 吧,可能 lua 的血统里,scheme 的成分比 C 更多一些。要不玩一下 Haskell ,增进对函数式编程的了解。C++ 借助 template 是可以玩玩函数式编程,但很少有人真的去用。进入 lua 的领域后,你得正正经经的理解一下了。

    Lua与C++不是一种语言,Lua的产生也不是为了让C++这个大奶高兴,它的地位是独立的。

    我在twitter上发了这样一些感慨:

    感觉这里面有百分之五十的问题都是c++如何导出所有类型给lua,lua如何调用c++成员变量、类成员、内部函数。这些人太纠结了!思路不对,就跟把c++当做高级c来使用一样。展开一点说,这种用法的来源,首先是设计人员脑子不清楚了,lua与c++的边界完全混在一起,没有把接口最小化,以及适当简化,就是c++完全贴到lua上。清晰地api(通用意义上的),就是定义适当的操作,可以扩展,但是不过分耦合。lua和c++应该是哑铃状连接,而不是水桶。

    为什么Lua与C++无缝整合有问题,原因很简单:任何一个有经验的程序员都知道,如果两个系统之间是紧密相连到成员函数成员变量都可以随便调用,那么这两个系统的耦合度一定是相当高,容易出现的问题就是难扩展、难修改、难维护。这两个系统不如直接整成一个系统算了。

    如何正确使用Lua与C++?

    首先第一个问题是,你的系统谁是主导?Lua还是C++?首先搞清楚这个问题。因为主导的部分代码将作为框架出现,负责调用或者响应事件、逻辑。如果Lua与C++的代码都做同样的工作,那么这个系统的设计是有问题的。

    第二个问题是,你的系统里面,作为主导部分想开放那些接口?(我们姑且认为Lua与C++的中间连接部分为接口interface)。两个系统之间,不需要完全整合,只要开放必要的接口或者说是API即可。在著名的《Designing Qt-Style C++ APIs》中,作者Matt总结了下面6个优秀API的特点:

    总而言之,Lua本身有它自身的特点,如函数式编程,尾调用,变量无类型等等,这些特点与C++是截然不同的,如果你非要把C++与Lua弄得无缝整合,将来一定会因为这个高耦合产生各种各样的问题。

    就如我在twitter中说的那样:编程弄得这么纠结,何必呢?!

  • for douban

    doubanclaim016a1cb97bb3d39b

  • 一个VARIANT引发的bug

    昨天一位同事跟领导讨论过程中提到,他认为微软Visual c++6.0编译器的最大优化有bug。因为以前没有使用最大优化的时候代码没有问题,把project setting改成最大优化以后就出现bug了。

    因为这个max speed optimization设置修改是我提出来的,所以感觉有必要看看原因到底是什么。因为我是不相信这种“微软编译器优化能导致接口调用出错”的说法,往往此类问题就出在我们自己的代码上面。

    在这个同事的电脑上重现了一下这个问题,然后回到我自己电脑上,果然也可以重现,这就有点意思了。

    在代码中加入断点,发现是某个接口函数调用失败,这也是那个同事所谓的“最大速度优化导致接口调用失败”说法的起源,不过我相信,这之前的代码一定已经有问题了。

    查看运行时的调用栈,在几个相关函数加入log信息,然后跑了一遍错误的情况(setting为最大优化),再跑一次结果正确的情况(setting为不优化)。然后使用winmerge比较两次log的文本,发现它们俩有不同的输入参数。

    为何同样的代码,只是修改了project setting就有不同的结果呢?难道真的是VC++出了问题被我这个同事抓到bug?

    我又跑了几次错误的情况,发现输入参数字符串的最后一部分是随机变化的(正常情况应该是不变的)。我记起一种可能性,当我们使用最大优化的时候,某些没有初始化的变量会有这种可能。

    从调用栈上溯,发现这个参数是来自另外一个接口,它的调用方式类似这样:

    CComVariant var;
    p->GetAddr(&var);
    CString str.Format("aaaa %d", var.uiVal);

    uiVal的定义是unsigned short,也就是一个2Bytes数据,可是查看GetAddr()这个函数,里面代码类似这样:

    HRESULT CAaaa::GetAddr(VARIANT* pVar)
    {      
         CComVariant var(m_addr); // 这里的m_addr的声明是BYTE m_addr;
         return var.Detach(pVar);
    }

    好像能抓到一些问题的原因了。我们查看VARIANT的定义可以发现它内部包含了一个union,里面有BYTE bVal;有unsigned short uiVal;有unsigned long ulVal;

    OK,原因很清楚了。我们在GetAddr中赋值的时候,只(使用)设置了VARIANT的联合中1个BYTE的数据,而我们在后面的代码里使用uiVal形式,实际上读取了2个BYTE,高位部分的数据是无效的。通过观察随机数的16进制格式也可以发现,正确数据应该为0x00,我们得到的错误结果都是0x5800,0x6300,0xCC00这样的。

    知道了问题的原因该如何修改呢?有两种办法,一个是在结果中也是使用bVal,这是最好的办法。另外,如果要使用比赋值时数据长度更宽的类型,一定要通过var.ChangeType(VT_UI2);这样的类型转换,保证高位部分数据有效。

    改完了这部分代码,程序在最大优化的设置下一样运行正确,根本就不是什么设置导致的问题,就是代码有问题。

    另外非常需要注意的是,这种bug跟优化不优化没有任何联系,而是跟CComVariant以及VARIANT这种复杂数据结构里面的union有关系,CComVariant好像没有对VARIANT的数值成员做清零操作,而是调用了VariantInit()。使用union的时候都需要注意类似的情况。

    我构造了一个test case可以在不设置最大优化的情况下一样出现类似问题。如果认为这是“最大速度优化导致接口调用失败”,只是看到了一种表象,真正的原因离着远呢。

  • Lua源代码阅读分析问题列表

    我个人的习惯是带着问题去研究一个新题目,比如这次阅读Lua代码,暂列下面这些问题。

    1)什么是基于栈、基于寄存器的虚拟机(VM)设计?Lua如何实现基于寄存器的设计?

    2)Lua如何解析一段代码,生成中间代码?

    3)Lua如何使用VM运行中间代码?

    4)Lua如何实现GC机制?

    5)ipairs与pairs的不同(这是前几天写代码时发现的)?

    6)Lua如何实现闭包功能?

    7)Lua如何实现协程功能?

    8)Lua与c语言交互时栈的变化?

    9)如何为Lua增加一个continue关键字?

    10)Lua代码中常用的C语言编程技巧有那些?

    11)table如何实现的?

    12)如何实现的hook机制?

    13)如何实现的debug机制?

    暂列这些,以后再添。