Lua C

转自lua程序设计第二版

Lua和C通信的主要方法时一个无所不在的虚拟栈。几乎所有的API调用都会操作这个栈上的值。所有的数据交换,无论是Lua到C还是C到Lua都通过这个栈来完成。
还可以通过这个栈来保存一些中间结果。以及解决Lua和C语言中间的两大差异:

  • Lua使用垃圾收集,而C要求显示地释放内存
  • Lua使用动态类型,而C使用静态类型

重入

Lua没有定义任何全局变量,它将所有的状态都保存在动态结构lua_State中,所有的C API都要求传入一个指向该结构的指针。这种实现使得Lua可以重入(如果 C 程序在一个脚本上调用解释器,该脚本调用一个 C 函数,而这个 C 函数又再次使用 Lua 解释器,这是允许的。)。

关键字

luaL_State 创建一个新环境,新环境中没有包含预定义的函数
luaL_close(lua_State* l)

LuaL_openlibs(lua_State* l)打开所有的标准库
LuaL_loadbuffer编译用户输入的每行内容。如果没有错误,返回0.并向栈中压入编译后的程序块。
lua_pcall将程序块从栈中弹出,并在保护模式中运行。如果发生错误就会向栈中压入一条错误消息。用lua_tostring可以获取这条消息,打印后用lua_pop从栈中删除。

压入元素

void lua_pushnil (lua_State *L);
void lua_pushboolean (lua_State *L, int bool);
void lua_pushnumber (lua_State *L, double n);
void lua_pushlstring (lua_State *L, const char *s,size_t length);
void lua_pushstring (lua_State *L, const char *s);

向栈中压入元素时,应该确保栈中有足够的空间。当Lua启动时,或Lua调用C语言时,栈中至少有20个空闲的槽。

//检查栈中是否有足够的空间
int lua_checkstack(lua_State * L,int sz)

查询元素

API中使用”索引”来引用栈中的元素。
第一个压入栈的为1,第二个为2,依次类推到栈顶。

使用负数来访问栈中的元素,-1表示栈顶元素,-2表示栈顶下面的元素。

检查元素是否为特定的类型

//例如lua_isnumber lua_isstring ...
int lua_is*(luaState* L,int index)

或者通过lua_type来返回栈中元素的类型。

从栈中获取元素

int lua_toboolean (lua_State *L, int index)
lua_CFunction lua_tocfunction (lua_State *L, int index);
const char *lua_tolstring (lua_State *L, int index, size_t *len);
lua_Number lua_tonumber (lua_State *L, int index);
const void *lua_topointer (lua_State *L, int index);
const char *lua_tostring (lua_State *L, int index);
lua_State *lua_tothread (lua_State *L, int index);
void *lua_touserdata (lua_State *L, int index);

不要在C函数之外使用在C函数内获得的指向Lua字符串的指针

lua_tolstring函数会返回一个指向内部字符串副本的指针,并将字符串的长度存入最后一个参数len中。这个内部副本不能修改,返回类型的const也说明了这点。Lua保证只要这个对应的字符串值还在栈中,那么这个指针就是有效的。当Lua调用的一个C函数返回时,Lua就会清空它的栈。

table操作

Get

BLUE = {r = 0,g = 0,b = 1}

#defien MAX_COLOR 255
//假设table位于栈顶
int getField(Lua_State *L,const char* key){
    int result;
    lua_pushstring(L,key);
    //获取background[key]
    lua_gettable(L,-2); 
    if(!lua_isnumber(L,-2)){
        error(L,"invalid component in BLUE color");
    }
    result = (int)lua_tonumber(L,-1) *MAX_COLOR;
    //删除数字
    lua_pop(L,1);
    return result;
}

lua_getglobal(L,"BLUE")
if(!lua_istable(L,-1)){
    error(L,"'BLUE' is not a table");
}

red = getfield(L,"r");
green = getfield(L."g");
blue = getfield(L,"b");

Set

    lua_pushstring(L,key);
    lua_pushnumber(L,value);
    //假设在调用钱table在栈顶(索引为-1),当压入key和value后,table就位于索引-3
    lua_settable(L,-3);

创建新的table

lua_newtable(L);
...
lua_setglobal(L,name)

C 调用Lua函数

基本调用

function f(x,y)
    return x + y
end
lua_getglobal(L,"f");
lua_pushnumber(L,x);
lua_pushnumber(L,y);
//完成调用(2个参数,1个结果,0表示错误处理函数索引)
if(lua_pcall(L,2,1,0) != 0){
    error(L,"error running funciton f:%s",lua_tostring(L,-1))
}
//检查结果
if(!lua_isnumber(L,-1)){
    error(L,"function 'f' must return a number");
}

z = lua_tonumber(L,-1);
//弹出返回值
lua_pop(L,1);

可变参数调用

void call_va(const char* func,const char* sig,...){
    va_list vl;
    //参数和结果的数量
    int narg,nres;

    va_start(vl,sig);

    //压入函数
    //遍历所有参数
    for(narg = 0;*sig,narg++){
        //检查栈中空间
        luaL_checkstack(L,1,"too many arguments");

        switch(*sig++){
            case 'd':
                lua_pushnumber(L,va_arg(vl,double));
                break;
            case 'i':
                lua_pushnumber(L,va_arg(vl,int));
                break;
            ...
        }
    }

    lua_getglobal(L,func);
    //压入参数
    //期望的结果数量
    nres = strlen(sig);
    //完成调用
    if(lua_pcall(L,narg,nres,0) != 0){
        error(L,"error calling '%s':%s",func,lua_tostring(L,-1));
    }

    //检索结果
    //第一个结果的栈索引  
    nres = -nres;
    //遍历所有结果
    while(*sig++){
        switch(*sig++){
            case 'd':
                if(!lua_isnuber(L,nres)){
                    error(L,"wrong result type");
                }

                *va_arg(vl,double *) = lua_tonumber(L,nres);
                break;
                ...
        }
    }

    va_end(vl);

}

Lua调用C

示例

//注册函数模型 返回一个整数,表示其压入栈中的返回值数量
typedef int (*lua_CFunction)(lua_State *L);

//正弦函数
static int l_sin(lua_State *L){
    //获取参数
    double d = lua_tonumber(L,1);
    //压入结果
    lua_pushnumber(L,sin(d));
    //结果的数量
    return 1;
}

//压入一个函数类型的值
lua_pushcfunction(L,l_sin);
//将这个值赋予全局变量mysin
//lua调用C函数时,并不依赖函数名,包的位置或可见性规则,而值依赖于注册时传入的函数地址。
lua_setglobal(L,"mysin");

//重新编译程序后即可在lua中调用mysin函数

C模块

C模块中只有一个公共函数,用于创建C模块。而其他所有函数都是私有的,在C语言中声明为static。

//所有要注册的函数
static const struct luaL_Reg mylib[] = {
    {"dir",l_dir},
    //结尾
    {NULL,NULL}
}

int luaopen_mylib(lua_State *L){
    luaL_register(L,"mylib",mylib);
    return 1;
}
require("mylib")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值