Lua小坑之整数

Lua小坑之整数

在最近的一次开发中,需要将两个整数做除法,例如以下简单语句:

c=a/b

由于a和b都是整数,因此我又想当然地认为c也是整数,而实际上Lua将c转换成浮点数,导致后续逻辑判断和处理都出错了。这又是Lua让人意外的一个地方,我很困惑设计者为什么要这么设计。在Lua 5.3的reference manual文档中,对此有明确说明:

Exponentiation and float division always convert integer operands to floats.

据说5.3版本之前,Lua甚至都不支持整数,只有浮点数。而我们的程序通常只有两种类型:整数和字符串,因此重新将计算结果转换回整数是个急需解决的问题。在翻看manual文档时,看到math.tointeger接口,试了一下,结果极为悲催,返回了nil值!这是搞个毛线啊?

幸运地是lua对C很友好,因此只好手工打造一个接口给Lua程序用:

static int bluaToInt(lua_State *L)
{
 assert(NULLP!=L);
 int intVal = 0;
 int type = lua_type(L,1);
 switch( type )
 {
 case LUA_TNUMFLT: 
 intVal = (int)luaL_checknumber(L,1);
 break;
 
 case LUA_TNUMINT:
 intVal=(int)luaL_checkinteger(L, 1);
 break;

 case LUA_TSTRING:
 intVal = BclStrToInt(luaL_checkstring(L,1));
 break;
 
 default:
 assert(0);
 break;
 }

 lua_pushinteger(L, intVal);
 return 1;
}

将上述函数注册到Lua中,定义为“ToInt”,然后在脚本中使用即可。由此上述示例代码变为:

c=ToInt(a/b)

这样就能确保c为整数类型。

家乡的味道

家乡的味道

孩子们放暑假,带他们回到了家乡,一个位于江西的典型四线小城市。一条河穿城而过,每天都有很多孩子在河里游泳、戏水,天气也不出所料地进入了烧烤模式。

家乡变化很大,对于很久没有回来的我来说,感觉已经有点陌生。以前熟悉的地方现在都改变了,印象中稻花飘香的田野现在盖满了楼房,我实在想不通这个小城怎么会有这么多楼房。所幸的是城市主干道没有改变,沿着这路我还能逐渐找回以前的记忆。

而最让我惊讶的是家旁边巷子里的那家馒头铺还在,还是一样的老面馒头、花卷以及我最爱的大肉包子!还是那家人在做各式面点,还是印象中的味道,甚至连营业时间都没有变:从早上6点到早上8点!到点就收摊,提前卖完就提前收摊。每次都是早早去排队买馒头和包子,晚了就没了,店家一如既往地没想着多卖点、多赚点。真希望这馒头铺能一直做下去,这样的味道能长久地保持下去。

 

愤怒!26人罹难!

愤怒!26人罹难!

大陆一个旅游团在台湾旅游,不幸遭遇严重车祸,全部罹难,真是让人悲痛,愿死者安息!新闻链接请点击这里

而港、台的一些评论实在令人不齿,深感愤怒!相关链接请点击这里

120周年

120周年

周末带孩子们去香港玩,其中一项就是慕名已久的山顶缆车。坦率地说,在大太阳底下排队晒一个多小时,再坐三分钟缆车,虽然沿途山顶的风光不错,但还是觉得十分乏味。个人觉得山顶缆车是一个『可以坐一次、没必要坐第二次』的项目。

而让我颇有感叹的是在山顶看到的一张宣传画:山顶缆车居然已有120年历史!沧海桑田之感油然而生。如果将其比作一部作品,这也算打磨百年,完全够格“工匠精神”了吧。就我从事的IT行业来说,有没有百年历史?目前有什么软件、通信项目能存活百年?

昨天经历的另一个百年项目是“天星小轮”,我非常喜欢,尤其喜欢那种有点破、有点旧的环境,时光都停止了,在繁华的维港悠闲地飘几分钟,感觉真好。

办理回港证

办理回港证

小苗的回港证(就是红本那个)下个月月中到期,不过考虑到想带小苗回老家过暑假(游泳、爬山、各种爽),实在不想中途再回深圳一趟,因此决定这个月就把事给办了。

1、资料

先说一下办证的一些必备资料以及相关细节:

(1)自己的港澳通行证。

(2)过关时打印的小标签,就是说明入境时间、停留时间的那张小纸条(网络上的大部分资料没有提到这个,事实上这个是要求的。当然也可能不同事务处或者办事员要求有差异)。

(3)小孩的原回港证、回乡证(网络资料同样没有提到回乡证,但我遇到的办事员要求检查回乡证)。

(4)小孩的照片、出生纸(有身份证亦可)。

(5)小孩的学籍表(如果没有在港入学,则需要另外填一个副署人的表,貌似没要求是港人,因此应该大陆人也可以,具体还是问事务处吧)。

(6)现场会要求填一张资料表,入境处贴了模板,照着填就好了。

(7)以上资料都无需复印,现场办事员自己会复印。

(8)办证费用是港币140元,请注意现场只接受现金或者刷“易办事”,不接受信用卡、银联、银通、八达通等各类卡。

2、流程

(1)首先是预约。在“香港政府一站通”网站,预约申请旅行证件即可。可以预约当日起24日之内的时间。建议及早预约,尤其是寒、暑假期间,几乎每天都是满满当当的。预约时登记出生纸,选择合适的时间和合适的入境事务处即可。

(2)提前大约半小时到入境事务处拿筹。太早了也没用,不会给派筹。比如预约的10点,大约9:30到即可。

(3)拿筹同时会给一张资料表填写,然后等着叫号。

(4)叫号后到相应的位置办理,主要是检查各类资料原件,办事员自己复印必要的资料。这个环节完事后,办事员会告诉到某个窗口前等待叫名字交钱。

(5)等着叫名字、交完钱,直接就能拿到新回港证,所有流程结束。如果资料都准备好、一切顺利的话,在入境事务处大约只需要半个小时左右。

3、入境事务处

作为一名标准大陆人,操一口标准南方普通话(没有香港同胞经常嘲笑的儿化音),我其实是比较怵去香港办事的。香港那曲折的小径、销魂的鸟语、高冷的白眼、迷一样的城市丛林,让我每次去都有莫名的恐慌感。由于办理回港证要求小孩必须亲自到场,为了避免出现带着孩子在香港街头四顾茫然的悲剧性场面,我决定先踩点,先比较一下大陆朋友们喜闻乐见的入境事务处,然后再决定最终预约。

从深圳湾出发的话,元朗入境事务处、西九龙入境事务处等经常被提及。而如果是从福田或者罗湖出发的话,可能其他事务处(比如火炭入境事务处)更合适一些。

这里说点题外话,网络上的一些资讯有很多问题:

(1)过时。比如西九龙入境事务处实际上已经不在油麻地了。

(2)无用。可能某些攻略是妈妈们写的,如果你对地形比较熟悉,自然很有帮助,如果你和我一样初到宝地,估计仍然会一头雾水。比如某些魔幻性的描述“沿着车流走两个路口,右拐。。。”,事实证明没有包含某些曲折小径的路口,而且诸如“右拐”、“左拐”之后,还有一大段弯曲的路要走,一时半会没找到,实在让人忐忑不安。作为一名工科男,我将给出理性的地图来描绘路线,一图胜过千言万语,真正的简约而不简单。

(3)混乱。有些人给出的建议实际上是办理回乡证,而不是办理回港证。我觉得这些人可能就是网络传说的“回帖不看帖”人士。

3.1、元朗入境事务处

这个是最近、最方便的事务处。

(元朗入境事务处已经搬离“富达广场”,搬入“元朗政府合署1楼”,因此原有资料已经不和事宜,删除。)

3.2、西九龙入境事务处

可能是暑假的原因,元朗事务处里人比较多,因此我决定继续踩点西九龙。这个点可能是走路最多的一个点,原因就在于从尖东到尖沙咀这段挺长、而且需要走路。

基本路程:(1)从深圳湾坐B2P,第一站下,到达天水围地铁站。(2)坐西铁(红磡方向)至尖东。(3)出闸口但是不出地铁站,沿着指示,步行至尖沙咀站B2出口。(4)沿金马伦道、加拿分道至金巴利街即可。如下图所示:

西九龙入境事务处
西九龙入境事务处

这个事务处的人也比较多。

3.3、沙田入境事务处

当我上网预约的时候,悲催地发现:上面两个事务处全满!只能预约到沙田入境事务处!此事充分说明:干活要乘早,拖延症害死人。不得已,再次走上踩点的旅程。

这个事务处是如此遥远,仅仅在地铁里就要度过漫长的一个多小时。同时,它又是如此的醒目,居然在一个政府大楼里,也就是“沙田政府合署”,沿路都有路牌指示,想迷路都不太可能,因此完全不需要上述地图指引。

基本路程:(1)从深圳湾坐B2P,第一站下,到达天水围地铁站。(2)坐西铁(红磡方向)至终点红磡。(3)步出西铁车门的一刻,你就能看到对面的东铁(罗湖方向),走过去,坐下来,到“沙田”站下,从B出口出。(4)沿着人行道、看着路标“沙田政府合署”的指示走即可。

再跑跑题。我在政府合署旁边的一个商场内发现了IKEA!作为深圳IKEA的常客,我兴冲冲地溜达过去参观一下,天呀,SO TINY!真是没有对比就没有伤害。

4、注意事项

排队的时候要保持好队形,避免被人误认为是插队。

如果你能操一口流利的白话,恭喜你,你完全可以和办事员谈笑风生。如果你和我一样只会说普通话(还好,是南方普通话),请保持低调、请保持同理心,紧紧地盯着显示屏,竖起耳朵仔细听广播。

最重要的是照顾好自己的小孩!

C向Lua函数传递table参数

C向Lua函数传递table参数

有时需要向函数传递相对比较复杂的数据,定义多个形参显得很难看,C语言函数中通常传递一个数据结构,而对于lua最直接的莫过于传递一个table数据。C调用lua函数时,也可以通过构造table数据传递给lua函数。

基本步骤比较简单,大致是(1)获取lua函数(2)在栈中构造一个table(3)向table中压入相应的数据(key-value)(4)执行lua函数。

以下伪码详细描述了这个过程:

......
lua_getglobal(L, "demoFunc"); // 获取Lua函数名

lua_newtable(L); // 创建一个table
lua_pushstring(L, "intVal");  //key为intVal
lua_pushinteger(L,1234);      //值为1234
lua_settable(L, -3);          //写入table
lua_pushstring(L, "strVal");  //key为strVal
lua_pushstring(L, "yxh");     //值为yxh
lua_settable(L, -3);          //写入table

lua_pcall(L,1,0,0); // 调用demoFunc函数
......
台湾旅游的广告

台湾旅游的广告

公然歧视大陆游客,欺人太甚!

涉嫌歧视的台湾旅游广告
涉嫌歧视的台湾旅游广告
涉嫌歧视的台湾旅游广告2
涉嫌歧视的台湾旅游广告2
Lua路径

Lua路径

在学习的路上踩坑不止,今天遇到这个坑是关于“路径”的。

在windows版本中,lua默认的路径包括当前路径,以及当前路径下的lua子目录。因此测试时,理所当然将所有lua文件都放在当前目录的lua子目录下。

切换到linux系统(debian 8),发现lua默认没有当前lua子目录。当然,可以修改lua文件,在require语句中明确增加lua来规避,例如以下语句:

local fsm = require "lua.services.fsm"

对此不同系统下的表现颇感迷惑。检查了一下Lua的代码,发现的确有差异。对于LUA_PATH_DEFAULT宏的定义,windows系统默认包含当前目录以及lua子目录,而linux系统居然默认指向“/usr/local”目录(以及该目录下的各类子目录),当然也包含了当前目录,然而却没有包含当前lua子目录。

统一两个系统的表现也很简单,无非是修改linux系统环境中的LUA_PATH_DEFAULT定义,增加当前lua子目录,例如:

"./lua/?.lua;" "./lua/?/init.lua;" \
 "./?.lua;" "./?/init.lua"
luaL_loadfile的坑

luaL_loadfile的坑

在众多demo中,都是使用这个函数加载lua文件,然后由C程序调用lua提供的function或者value。但是调用该函数后,如果直接使用lua_getglobal去获取对应的lua函数,只会获取到空值。

luaL_loadfile实际调用了lua_load函数来加载lua文件。需要注意的是:lua_load仅加载lua代码块,但是并不运行。如果成功,会加载一个编译好的代码块作为一个匿名函数放置在栈顶。只有首先执行这个代码块,lua的vm才能最终知道各函数、变量等信息。

调用luaL_loadfile之后,应当接着调用lua_pcall执行匿名代码块,后续C代码才能有效调用Lua的函数。这样显然是比较繁琐的,lua中又提供了luaL_dofile宏来封装这两步过程:(1)加载;(2)执行。

因此,一般情况下,应该使用luaL_dofile来替代luaL_loadfile。

鸡肋的面向对象

鸡肋的面向对象

最近在研究Lua语言,主要参考Lua语言文档。简单地做了一些练习,感觉有点新鲜,也有点不适。

其中关于“面向对象”的章节实在太诡异,太拧巴了。单是那莫名其妙的冒号“:“就让人抓狂,更不用说对table的各种元操作。太夸张了,这是认真的么?作为有C++、python等语言背景的开发人员,我不得不说:这简直是为了面向对象而面向对象,无论是定义方式还是实现方式都太烂了!table固然让人击节赞叹,扭曲她去实现所谓的面向对象,有种美女变野兽的残暴感。

如果使用Lua语言,根本没有必要在意面向对象。Lua语法如此魔性,使用者应该抛弃面向对象的思维方式,而直接走函数式编程路子,堪称完美!