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, const char *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承担了配置文件格式检查的工作,假设你自己写解析程序。这一段代码不会少;其次。你能够在配置文件里写凝视,相同假设你自己写解析程序,也须要考虑跳过凝视的问题;最后。配置文件里能够做很多其它的灵活配置。比方,

-- 依据环境变量,灵活的定义窗体大小。
if os.getenv("DISPLAY") == "small" then
width = 100
height = 100
else
width = 500
height = 500
end

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中定义的颜色。 else if(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); return 0;
}
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"元方法时发生的错误(这个错误和被调用的函数无关。)。 */

高速掌握Lua 5.3 —— 扩展你的程序 (1)的更多相关文章

  1. Lua学习笔记4. coroutine协同程序和文件I/O、错误处理

    Lua学习笔记4. coroutine协同程序和文件I/O.错误处理 coroutine Lua 的协同程序coroutine和线程比较类似,有独立的堆栈.局部变量.独立的指针指令,同时又能共享全局变 ...

  2. [转] 扩展微信小程序框架功能

    通过第三方 JavaScript 库,扩展微信小程序框架功能. 扩展微信小程序框架功能(1)——Promise ES6 对 Promise 有了原生的支持,但微信开发者工具更新版本(0.11.1122 ...

  3. 找不到 main 方法, 请将 main 方法定义为: public static void main(String[] args) 否则 JavaFX 应用程序类必须扩展javafx.应用程序类必 须扩展javafx.application.Application”

    用eclipse写代码的时候,写了一个简单的程序,编译的时候突然出现“错误: 在类 com.test.demo 中找不到 main 方法, 请将 main 方法定义为: public static v ...

  4. 零基础攻略!如何使用kubectl和HPA扩展Kubernetes应用程序

    现如今,Kubernetes已经完全改变了软件开发方式.Kubernetes作为一个管理容器化工作负载及服务的开源平台,其拥有可移植.可扩展的特性,并促进了声明式配置和自动化,同时它还证明了自己是管理 ...

  5. C#构建可扩展的应用程序(插件)

    构建可扩展的应用程序,特别是对于WinForm应用程序是特别有好处的.我们知道,企业的需求是瞬息万变的,企业在使用软件的过程中,很可能对于现有的需求有变动甚至是提出新的需求来,可是我们的软件已经部署在 ...

  6. 正确lua简单的扩展,可以加速相关C++数据。

    很早的时候,我有一件事纠结.如果,我在这里C++打开界面脚本.使用C++其中一个目标,和.我的程序有很多不同的lua虚拟机.每个虚拟机与一个关联C++对象,它是多线程,那么如何快速应利用这个好时机lu ...

  7. 高速掌握Lua 5.3 —— Lua与C之间的交互概览

    Q:什么是Lua的虚拟栈? A:C与Lua之间通信关键内容在于一个虚拟的栈.差点儿全部的调用都是对栈上的值进行操作,全部C与Lua之间的数据交换也都通过这个栈来完毕.另外,你也能够使用栈来保存暂时变量 ...

  8. lua table面向对象扩展

    一 .table扩展 -- 返回table大小 table.size = function(t) local count = 0 for _ in pairs(t) do count = count ...

  9. CommandExtra.lua --游戏命令扩展

    --[[作者信息: Command Extra (游戏命令扩展) 作者QQ:247321453 作者Email:247321453@qq.com 修改日期:2014-3-12 功能:添加额外的命令.G ...

随机推荐

  1. 140730暑期培训.txt

    1.大数加减法    思路分析:        1.将数据当做字符串输入(gets(s))        2.将字符型转换为整型,逆着存            char? int      i=0,j ...

  2. docker创建自己的镜像并配置nginx

    前言 最近在研究docker,记录一下如何创建一个属于自己的镜像 本次使用linux版本为centos7.4(centos6也可以使用docker,只不过有部分功能只有7才有) 本次创建的镜像为cen ...

  3. mybatis&Hibernate区别

    mybatis是一个不完全的orm框架,因为mybatis需要程序员自己写大量的sql,需要程序员对sql的掌握比较高,不过mybatis可以通过xml文件可以灵活的配置要运行的sql语句,将sql与 ...

  4. Python 的 if __name__ == '__main__'

    Python 文件 最后部分会有: if __name__ == '__main__': TestRLSO()……………… 1)首先,这是一个判断语句. 表示执行的是此代码所在的文件.如果这个文件是作 ...

  5. JavaScript中逗号运算符

    JavaScript中逗号运算符(,)是顺序执行两个表达式.使用方法: expression1, expression2 其中expression1是任何表达式. expression2是任何表达式. ...

  6. Evernote如何邮件分享

    把你的笔记通过邮件发送给别人,从而实现分享

  7. Google Map 符号

      符号 简介 如果您想在标记上使用基于矢量的图标,或者向多段线添加图像,便可使用符号. 标记支持使用光栅图像以及矢量图像.请参阅有关定制标记图标的文档. Symbol 是一种可显示在 Marker  ...

  8. 转:使用Mosquitto-Auth-Plugin对mqtt客户端进行验证

    https://www.lixiaodong.com/?p=1631.安装需要的包sudo apt-get install libc-ares-dev libcurl4-openssl-dev lib ...

  9. RHEL7 -- 识别文件系统和设备

    逻辑卷依赖于设备映射程序(DM)内核驱动程序. 比如有个逻辑卷组rhel中有一个逻辑卷root,对应的设备为/dev/rhel/root.符号链接/dev/rhel/root指向/dev/dm-< ...

  10. HTTP请求流程(二)----Telnet模拟HTTP请求

    http://www.cnblogs.com/stg609/archive/2008/07/06/1237000.html 上一部分"流程简介", 我们大致了解了下HTTP请求的流 ...