背景
为了保证lua脚本返回结果的正确性,我写了一些用于检查脚本正确性的额外脚本,在开发环境下每个需要检查的函数里面调用额外脚本,在生产环境下注释掉这些调用。由于脚本数目比较多,手工增删实在够繁琐,于是想用一种更自动化的方法来完成这个任务。这算一个提高生产力的小需求吧。
环境
虽说C++编译器,操作系统什么的无所谓,不过为了完整性还是写出如下
OS: Windows 7 64bit
IDE: Visual Studio 2010(VC)
LIB: lua 5.1
方案描述
1、为了使得接口更容易复用,项目中的Lua脚本返回值使用统一的格式(自定义的表),这样所有脚本可以用一个检测函数检验正确性。使用额外脚本作为检验函数,而不是在C程序中使用写检验函数的原因是:脚本灵活,可以按需更改检验内容而不用重新编译程序,而且写起来也更为方便。
2、由于调用的脚本都会返回结果到C程序中,那么我们可以在C程序中统一调用检测函数,而不是在脚本中分别调用,这样就可以实现自动化的目的。
3、考虑到开发和生产环境中的不同侧重点(正确和效率),使用编译开关来控制C程序中调用的检测函数的部分,这样可以做到两者兼顾,而且在切换环境时不用更改任何代码。
代码示例
1、脚本部分
--待检测的脚本 function test(a) a = a or "" local ret = {} ret.membera = "a"..a --手误,应该是memberb ret.membreb = "b"..a return ret end
--检测脚本 function CheckResult(result) if type(result.membera) ~= "string" or type(result.memberb) ~= "string" then error("result members must be string") end return result end
以上两个函数是用来作示例用的代码,在实际开发中,需要根据业务来写出适合项目的脚本,总结了以下几条规则:
(1)、检验返回值中有没有缺少必要元素或者类型不正确,一般是把返回值必要元素写成一个对照用的表。然后遍历表,对比之即可。
(2)、检验返回值中有没有多余的元素,这个做法可以参考上一点
(3)、检验返回值中的元素是否在业务逻辑上有效,例如用来表示长度/个数的元素是否整数,是否大于0。有依赖的元素依赖关系是否正确,等等。
(4)、检验函数最后应把检验完成的结果作为返回值返回给调用者,以便后面C代码使用。
2、C语言接口部分
//从lua脚本获取一个函数 int C2lua::AddFunction(const char *func) { //check lua environment if ( lua == NULL) { return ERR_LUA; } //check function name if (func == NULL) { return ERR_PARA; } //some codes here #ifdef _DEBUG lua_getglobal(lua, "CheckResult"); #endif // _DEBUG lua_getglobal(lua ,func_name); return ERR_NONE; }
//执行并处理返回结果 int Execute() { int ret = 0; //check lua environment if ( lua == NULL) { return ERR_LUA; } //check error if (lua_pcall(lua, para_num, 1, 0))//call function { ret = ConvertLuaError(lua_tostring(lua ,-1)); goto CRET; } #ifdef _DEBUG if (lua_pcall(lua, 1, 1, 0))//call CheckResult { ret = ConvertLuaError(lua_tostring(lua ,-1)); goto CRET; } #endif //process result //some codes here CRET: return ret; }
以上两块代码是我从项目中截取出来的部分代码,这是一个类的成员函数,其中某些未定义的函数和变量都是其他的成员。
整个流程如下:
(1)、首先压入检测函数CheckResult
(2)、然后压入待调用函数
(3)、之后得到返回结果
(3)、再后把结果作为参数压入到检测函数
(4)、最后得到验证后的结果
程序中DEBUG宏的使用可以达到开发生产两不误的效果。
3、其他事项
有一点需要注意的是:如果有些功能的返回值检测不能写到同一个检测函数里面,那么就表明这些功能和以前的功能在业务上分属两个不同部分。那么在C接口函数在设计和实现上也应该分开。然后就可以按照上面的方法为每个部分设计单独的数据交互格式以及检测函数。也能实现自动测试的目的。
后
总而言之呢,只要遇到这种机械化的重复劳动,一定用计算机来帮助我们解决。解放时间和双手,可以做更多有创造性的工作,这样才能算合格的软件工程(设计)师 ^^
杀花~
D大觉得Lua和Python各有什么特点?
lua环境的库很小巧,只有几百K的样子.语法和内置库函数也比较少.没有Python那么功能强大。和其他静态语言尤其是C语言可以很方便的交互,而且交互性能很高,适合做多语言混编中的业务逻辑部分。
Python自身功能很强大,也比较庞大,函数很多,多语言交互不如Lua那么容易,更适合做为独立程序运行。
如此,受教了,有空也来玩玩Lua~
统计了一下,一共只有19817行!
http://fanfou.com/photo/xs4w4GqcaMI
另据ssword说unix v6只有9k行
是很小巧,我这里也有V6的代码,不到1W行。
V6的源码里面C语言语言还用的是最老的那种吧,看起来好别扭….
MIT那个教学的用修改版 xv6好像是用ANSI C写的,好想有一天能读懂它们啊!
现在也有好多老式风格的C代码在各种常用的东西里面哪。例如GCC的标准运行库glibc,里面有好多这样的代码。
以上摘自glibc 2.14,不过咱们使用的标准库接口都是ansi格式的。
其实xv6很容易就看懂了,主要在进程(系统调用和其他trap)和内存管理(虚拟内存布局)那块,52同学要认真看上一周我估计就能八九不离十了。
哇卡卡,D大高估我的水平了 ==
话说你看过xv6的源码吗?
没有没有,代码不是很难懂,我相信你。
这个blog里面还有xv6的内存管理部分的解析呢
https://www.mydavelv.net/2010/12/06/xv6%E5%86%85%E5%AD%98%E5%B8%83%E5%B1%80/