在 C++ 中遍历 Lua table

2007-11-16 23:13 | by 2ndboy

  最近一个项目里要用到 Lua,于是有机会来学习如何在 C++ 里嵌入 Lua。用编译型语言和脚本语言协作来开发软件是不错的主意,Emacs 的 C + Lisp 就是一个展示这种具有良好扩展性和弹性架构很好的例子。其实我们身边还有很多这样的例子,比如在浏览器里使用 JavaScript,这就是在宿主程序里通过脚本语言调用宿主功能最典型的例子。UltraEdit 的新版里也集成了通过 JavaScript 来使用编辑器功能的特性。

  今天遇到了一个问题,就是通过 Lua C API 来取一个 table 中的数据。貌似 Lua 里没有判断指定 key 是否存在的 API。如果直接 lua_pushstring() 然后再 lua_gettable(),而指定的 key 又不存在的话程序会直接退出,比较的不爽。

  Google 了一把发现一种遍历 table 的方法,这样就可以在遍历的过程中去检查指定的 key 是否存在了。可以用 lua_next() 来遍历 table,但是这个 API 理解起来还是需要点时间的,特此记录一笔。使用 lua_next() 的一般形式是:

  1. // 进行下面步骤前先将 table 压入栈顶
  2.  int nIndex = lua_gettop( pLua )// 取 table 索引值
  3.  lua_pushnil( pLua )// nil 入栈作为初始 key
  4.  while( 0 != lua_next( pLua, nIndex ) )
  5.  {
  6.      // 现在栈顶(-1)是 value,-2 位置是对应的 key
  7.      // 这里可以判断 key 是什么并且对 value 进行各种处理
  8.      lua_pop( pLua, 1 )// 弹出 value,让 key 留在栈顶
  9.  }
  10.  // 现在栈顶是 table

lua_next() 这个函数的工作过程是:
1) 先从栈顶弹出一个 key
2) 从栈指定位置的 table 里取下一对 key-value,先将 key 入栈再将 value 入栈
3) 如果第 2 步成功则返回非 0 值,否则返回 0,并且不向栈中压入任何值

第 2 步中从 table 里取出所谓“下一对 key-value”是相对于第 1 步中弹出的 key 的。table 里第一对 key-value 的前面没有数据,所以先用 lua_pushnil() 压入一个 nil 充当初始 key。

注意开始的时候先用 lua_gettop() 取了一下 table 在栈中的正索引(前面说过了,在进行这个 lua_next() 过程之前先将 table 入栈,所以栈大小就是 table 的正索引),后面的 lua_next() 过程中不断的有元素出入栈,所以使用正索引来定位 table 比较方便。

到了 table 中已经没有 key-value 对时,lua_next() 先弹出最后一个 key,然后发现已经没有数据了会返回 0,while 循环结束。所以这个 lua_next() 过程结束以后 table 就又位于栈顶了。

  刚接触 Lua 不久,所以遇到一个问题罗嗦了大半天,其实 Lua 跟宿主打交道都靠这个 stack,这一点跟 MSIL 很像!掌握了 stack 的使用以后在 C/C++ 里嵌入 Lua 就不难了。

画展 & 吴山 & 征曲

2007-10-21 22:31 | by 2ndboy

  最近工作实在有点忙,Blog 更新频率明显下降。

  周末跟同事一起去看了吴冠中的画展。画展在中国美院旁边,我乘公交在西湖边的少年宫下车,一路沿着西湖走到美院。众同事早已到齐,于是一起进去看画展,门票是象征性的五块钱。我对高雅艺术向来接触甚少,只是凭着个人好恶来欣赏,写实的作品还是比较喜欢的,但是抽象的就看不懂啦。发现我比较喜欢的都是写实的风景画作,很喜欢一副叫《双燕》的作品!

  看完画展一行人来到河坊街吃饭,说起来惭愧,在杭州呆了这么些年,我还是第一次到这个塞满了旅游者的地方。街道两边令琅满目的小玩意真不少,还有各色小吃。我们在同事推荐的推荐下到状元馆吃面,东坡肉面现在想起来都要流口水。

  酒足饭饱后去爬吴山,比起上次我们去的十里琅珰,这实在是入门级的爬山,一会儿就到了顶上的一座凉亭。到凉亭的二层以后可以纵览大半个西湖,还能看到不远处的城隍阁,风景不错!顺便提一句,现在正是桂花开放的季节,上山时伴着一路的甜甜桂花香,秋高气爽的时节里爬爬山,真是不错的享受!

  老哥不久前喜得贵子,但是由于工作原因不能经常看到小孩,今天跟我说居然给我侄子写了一首歌,真是太有才啦!美中不足的是有词无曲,现贴出歌词征集相配的曲一首,希望有高人路过时小露一首:)

《爱的记号》

宝宝 宝宝 你是爸妈的骄傲
一切的辛劳 只为你快乐地长高
宝宝 宝宝 我们为你自豪
偶尔也会跌倒 但不能放弃微笑

不求你什么回报 健康快乐最重要
人生大道千万条 幸福靠自己创造

宝宝 宝宝 你是爸妈的骄傲
成长有几多烦恼 记得向前奔跑
宝宝 宝宝 我们为你自豪
别做温室的小苗 要在巅峰上舞蹈

这世界多么美妙 莫被琐事打扰
认清自己的目标 坚持不懈就好

有天我们会变老 不能陪你天涯海角
别怪爸妈的唠叨 你是咱家爱的记号

快进人生

2007-10-14 18:01 | by 2ndboy

  的确就像是某影评说的那样,《Click(神奇遥控器)》是部既能让你大笑又能让你哭的好电影!

  面对工作跟家庭,你是否总是以工作为重呢?面对生活挫折,你是否总是想快进人生把他们跳过呢?建筑设计师 Michael 因为得到了一支可以遥控人生的神奇遥控器,用它来跳过与妻子的争吵、生病、跟父母家人的聚餐从而错失了跟家人在一起的美好时光,当后悔的时候却已无力回天。

  有了神奇遥控器,你可以跳到生活的任意一个章节,你从自己生活的主角变成了一个旁观者。其实根本不用什么遥控器,你的真实想法就决定了你的人生态度,当你想要忽略一些东西的时候,你自然会想处于自动导航模式的 Michael 一样,人在而神离。

  男主角是亚当·桑德勒,曾经看过他的《50 First Dates(初恋 50 次)》,是个不错的有自己特色的演员。女主角是我非常喜欢的凯特·贝金赛尔,从《Pearl Harbor(珍珠港)》开始熟悉她,更喜欢她在《Serendipity(缘分天注定)》里面的表现,不过这部片子里她的戏份不多。

  绝对是部值得一看的好电影,笑料百出也非常感人,推荐!

《Reign Over Me》&《不能说的秘密》

2007-9-13 23:08 | by 2ndboy

  近来工作超忙,不知不觉已经一个月没有更新啦,今天来说说最近忙里偷闲看的两部电影。

  《Reign Over Me》,国内翻译成《从心开始》。在猪猪乐园看到这部电影的时候并没有什么期望值,只是抱着随便看看的念头下载。等到开始看的时候才发现两位主演居然都很熟悉,一位是出演过《Hotel Rwanda》和《Crash》的 Don Cheadle。另一位是我非常喜欢的 Adam Sandler,从之前看过的《Click(人生遥控器)》开始,我就发现亚当·桑德勒貌似开始转型啦,他在这部片子里的表现非常出色,证明了自己绝对不是只能演搞笑片而已。片子的前半部分有一些还算轻松的铺垫,到了后面感情爆发的时刻几乎可以感染任何静静欣赏的人!绝对是一部表现爱、亲情与思念的经典好片,强烈推荐观看!!!
Reign Over Me

  据说《不能说的秘密》是周杰伦的导演处女作,某同事 mm 说居然从这部感情片里看出了惊悚片的味道,但还是强烈推荐,好奇之余就找来看了一下,发现果然是部不错的电影。两位女演员绝对是片中的一大亮点!其次就是配乐,强烈建议找来电影原声听听!发现一个现象(也许只是巧合),蔡琴好像已经成了华语电影中经典好歌的代名词,《无间道》里用的是《被遗忘是时光》,《不能说的秘密》里用的是蔡琴的《情人的眼泪》,不过说真的,在稍大一点的空间里放蔡琴的歌,然后安静的欣赏,确实是一种享受。
桂纶镁

  其实最近看过的电影还有《The Bourne Ultimatum(谍影重重III)》,《Pathfinder(征服者)》和《Cashback(超市夜未眠)》。伯恩的伸手还是一如既往的令人叹为观止,不愧为好莱坞塑造的又一位孤胆英雄。《Cashback》改编自一部著名的 18 分钟短片,风格有些另类,很搞笑,但也是不错的片子。

根据图片文件头判断图片类型

2007-8-10 20:57 | by 2ndboy

  发现很久没有写过技术话题啦,赶紧来写一篇:)

  近来项目中需要从拿到的各种图片数据中分辨出图片格式来,于是 Google 一番后小有所得,拿出来分享一下。

  先来说 PNG 格式,这里有 PNG 格式的规范文档,从文档里可以看到,所有 PNG 格式文件的前 8 个字节都是一样的,可以用这个来判断。以下代码都假设 pData 指向图片数据:

  1. if( 0 == memcmp( pData, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8 ) )

  JPEG 格式可以参考这个文档,文档里面有这样一句话“you can identify a JFIF file by looking for the following sequence: X’FF’, SOI, X’FF’,
APP0, <2 bytes to be skipped>, “JFIF”, X’00’”,所以可以这样判断:

  1. if( 0xFF == pData[0] && 0xFF == pData[2] && 0 == memcmp( &pData[6], "JFIF\x00", 5 ) )

  GIF 格式的文档可以看这里,GIF 文件的前 3 个字节都是“GIF”,接下来的 3 个字节是版本号,可能的版本号貌似只有两种“87a”和“89a”,所以可以这样判断数据是否是 GIF 格式:

  1. if( 0 == memcmp( pData, "GIF87a", 6 ) || 0 == memcmp( pData, "GIF89a", 6 ) )

  TIFF 格式的文档在这里,TIFF 文件的前两个字节不是“II”就是“MM”(美眉?),“II”代表 Intel 字节顺序,“MM”代表 Motorola 字节顺序(也就是网络字节顺序)。接下来的两个字节始终是“\x00\x2A”,所以可以这样来判断:

  1. if( ( 0 == memcmp( pData, "II", 2 ) || 0 == memcmp( pData, "MM", 2 ) ) && 0 == memcmp( &pData[2], "\x00\x2A", 2 ) )