高速掌握Lua 5.3 —— 扩展你的程序 (1)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了高速掌握Lua 5.3 —— 扩展你的程序 (1),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6593字,纯文字阅读大概需要10分钟。
内容图文
Q:怎样在C中将Lua作为配置文件语言使用?
A:
“config.lua”文件里:
-- window size
width = 200
height = 300
“main.c”文件里:
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
void error(lua_State *L, constchar *fmt, ...)
{
// 逐一取出參数并打印到标准错误输出。
va_list argp;
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
lua_close(L); // 关闭Lua状态机。
exit(EXIT_FAILURE); // 以失败退出。 } void load( char *filename, int *width, int *height) { lua_State *L = luaL_newstate(); luaL_openlibs(L); /* luaL_loadfile(): * 读取配置文件,并将当中的内容编译为"chunk"放入虚拟栈中。
* lua_pcall(): * 使用保护模式调用虚拟栈中的函数。
被调用的函数应该遵循下面协议: * 被调用的函数应该被首先入栈。接着把參数按正序入栈(第一个參数首先入栈)。
* 第二个參数代表參数个数;第三个參数代表返回值个数; * 第四个參数代表是否使用自定义的错误处理函数。
* 当函数调用完毕之后,全部的參数以及函数本身都会出栈。而函数的返回值则被入栈。 */
if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0)) error(L, "cannot run configuration file: %s", lua_tostring(L, - 1)); // 获取配置文件里的全局变量。 lua_getglobal(L, "width"); // 将Lua环境下名为"width"的全局变量的值入栈。 lua_getglobal(L, "height"); // 将Lua环境下名为"height"的全局变量的值入栈。 // 推断全局变量的值是否为数值。 if (!lua_isnumber(L, - 2)) // 上面"width"先被入栈,所以-2是"width"。 error(L, "`width‘ should be a number\n"); if (!lua_isnumber(L, - 1)) // -1是"height"。 error(L, "`height‘ should be a number\n"); // 将全局变量的值转换为浮点数。 *width = ( int)lua_tonumber(L, - 2); *height = ( int)lua_tonumber(L, - 1); lua_close(L); } int main( void) { int width = 0, height = 0; load( "config.lua", &width, &height); printf( "width = %d, height = %d\n", width, height); return 0; }prompt> gcc main.c -llua-ldl-lm-Wall
prompt>./a.out
width =200, height =300
看完这个样例是否会认为使用Lua作为配置文件语言有些不值?只为了获取两个变量的值,却写了这么一大段代码。
可是使用Lua确实有其优势。
首先Lua承担了配置文件格式检查的工作,假设你自己写解析程序。这一段代码不会少;其次。你能够在配置文件里写凝视,相同假设你自己写解析程序,也须要考虑跳过凝视的问题;最后。配置文件里能够做很多其它的灵活配置。比方,
-- 依据环境变量,灵活的定义窗体大小。ifos.getenv("DISPLAY") == "small"then
width = 100
height = 100else
width = 500
height = 500end
Q:怎样在C中使用Lua的”table”?
A:我们在上一个样例的基础上继续扩展程序。
“config.lua”文件里:
-- window size.
width = 200
height = 300
-- window‘s background color.
-- 配置文件里能够自定义颜色。
ORANGE = {r = 255, g = 128, b = 0}
-
-background = ORANGE-
-background = {r = 128, g = 0, b = 255}
background = "BLUE" -- 也能够直接使用C中定义的颜色。
“main.c”文件里:
#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <lua.h>#include <lauxlib.h>#include <lualib.h>#define MAX_COLOR 255 // 颜色分量的最大值。
struct ColorTable {
char *name;
unsigned char red, green, blue;
} colortable[] = { // C中定义的颜色。
{"WHITE", MAX_COLOR, MAX_COLOR, MAX_COLOR}, {"RED", MAX_COLOR, 0, 0}, {"GREEN", 0, MAX_COLOR, 0}, {"BLUE", 0, 0, MAX_COLOR}, {"BLACK", 0, 0, 0}, {NULL, 0, 0, 0} // sentinel }; void error(lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); vfprintf(stderr, fmt, argp); va_end(argp); lua_close(L); exit(EXIT_FAILURE); return ; } void setfield(lua_State *L, const char *index, int value) { lua_pushstring(L, index); // 将"key"入栈。
lua_pushinteger(L, value); // 将"value"入栈。 /* 将指定的索引位置(-3)作为"table",将索引位置(-1)作为"value",将索引位置(-2)作为"key", * 做相当于"table[key] = value"的工作。之后将"key"和"value"出栈。 */ lua_settable(L, -3); return ; } // 获取"table"中元素"key"的值(此函数假设"table"在栈顶)。
int getfield(lua_State *L, const char *key) { int result = 0; lua_pushstring(L, key); // 将"key"入栈。
/* 从给定的索引位置(-2)获得"table",从栈顶位置获得"key", * 弹出"key",将"table[key]"的结果入栈。 */ lua_gettable(L, -2); if (!lua_isinteger(L, -1)) error(L, "invalid component in background color"); result = lua_tointeger(L, -1); //"table[key]"的结果即是颜色分量值。 lua_pop(L, 1); // 弹出颜色分量值,保证栈的状态与调用该函数时一样。 return result; } void setcolor(lua_State *L, struct ColorTable *ct) { lua_newtable(L); // 创建一个"table"并将其入栈。 setfield(L, "r", ct->red); /* table.r = ct->r */ setfield(L, "g", ct->green); /* table.g = ct->g */ setfield(L, "b", ct->blue); /* table.b = ct->b */ // 将栈顶的元素出栈(实际为上面创建的"table"),并使用名为"name"的全局变量存储。 lua_setglobal(L, ct->name) return ; } void load(lua_State *L, char *filename, int*width, int*height, int*r, int*g, int*b) { if(luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0)) { error(L, "cannot run configuration file: %s", lua_tostring(L, -1)); } lua_getglobal(L, "width"); lua_getglobal(L, "height"); lua_getglobal(L, "background"); // 将Lua环境下名为"background"的全局变量的值入栈。
if(!lua_isnumber(L, -3)) { error(L, "`width‘ should be a number\n"); } *width = (int)lua_tonumber(L, -3); if(!lua_isnumber(L, -2)) { error(L, "`height‘ should be a number\n"); } *height = (int)lua_tonumber(L, -2); // 假设"background"值是个字符串。那么说明使用C中定义的颜色。 if(lua_isstring(L, -1)) { const char *colorname = lua_tostring(L, -1); int i = 0; // 寻找使用的哪一种颜色。 while((colortable[i].name != NULL) && (strcmp(colorname, colortable[i].name) != 0)) { ++i; } if(colortable[i].name == NULL) { error(L, "invalid color name (%s)", colorname); } else { // 获取颜色的分量。
*r = colortable[i].red; *g = colortable[i].green; *b = colortable[i].blue; } } // 假设"background"值是个字符串,那么说明使用Lua中定义的颜色。
elseif(lua_istable(L, -1)) { // 获取颜色的分量。 *r = getfield(L, "r"); *g = getfield(L, "g"); *b = getfield(L, "b"); } else { error(L, "invalid value for `background‘"); } return ; } int main(void) { int i = 0; int width = 0, height = 0; int r = 0, g = 0, b = 0; lua_State *L = luaL_newstate(); luaL_openlibs(L); while(colortable[i].name != NULL) { setcolor(L, &colortable[i++]); // 将C中定义的颜色逐一初始化到Lua的"table"中。 } load(L, "config.lua", &width, &height, &r, &g, &b); lua_close(L); printf("width = %d, height = %d\n""red = %d, green = %d, blue = %d\n", width, height, r, g, b); return0; }
prompt> gcc main.c -llua-ldl-lm-Wall
prompt>./a.out
width =200, height =300
red =0, green =0, blue =255
附加:
1、
/* int lua_pcall(lua_State *L, int nargs, int nresults, int msgh)
* 以保护模式调用具有"nargs"个參数,"nresults"个返回值得函数。
函数在第一个參数的前一个位置。 * 保护模式指的是当调用出错时不会报错,而是返回一个错误码同一时候将错误信息入栈。
* 当调用成功时,函数返回0。将函数名以及參数出栈,之后将函数的返回值入栈。 * 不管函数返回多少个返回值,Lua会调整为你须要的数量,忽略多余的或者将不够的补为"nil"。 * 当调用出错时,函数返回非0值。将函数名以及參数出栈, * 以错误信息作为參数,执行虚拟栈中索引"msgh"处的出错处理函数, * 将出错处理函数的返回值作为"lua_pcall"的返回值入栈。
* "msgh"为0代表没有错误处理函数,错误处理函数必须要在被调用函数和其參数入栈之前入栈。
* 典型的使用方法中,错误处理函数被用来给错误消息加上很多其它的调试信息,比方栈跟踪信息。
* 这些信息在"lua_pcall"返回后。因为栈已经展开,所以收集不到了。 * lua_pcall 函数会返回下列常数(定义在"lua.h"内)中的一个: LUA_OK (0): 成功。 LUA_ERRRUN: 执行时错误(一般错误)。
LUA_ERRMEM: 内存分配错误(此种情况,Lua不会调用错误处理函数)。 LUA_ERRERR: 在执行错误处理函数时发生的错误(此种情况。Lua不会再次调用错误处理函数)。 LUA_ERRGCMM: 在执行"__gc"元方法时发生的错误(这个错误和被调用的函数无关。)。
*/
原文:http://www.cnblogs.com/wzjhoutai/p/7326942.html
内容总结
以上是互联网集市为您收集整理的高速掌握Lua 5.3 —— 扩展你的程序 (1)全部内容,希望文章能够帮你解决高速掌握Lua 5.3 —— 扩展你的程序 (1)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。