lua Capi

一、C环境使用mingw 的gcc

可从这里下载完整版那的mingw: http://pan.baidu.com/s/1crx1s

可参考该设置环境变量及编译lua的教程:https://www.cnblogs.com/jessicas/articles/4477655.html?tdsourcetag=s_pctim_aiomsg

lua要使用该mingw进行编译;记住不要使用5.1.5版本的lua;编译会有问题

我使用sublime进行编码,可以设置如下的编译配置:

复制代码
{
    "working_dir": "$file_path",
    "cmd": "gcc -Wall \"$file_name\" -o \"${file_base_name}.exe\" -llua",
    "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
    "selector": "source.c",
 
    "variants": 
    [
        {   
        "name": "Run",
            "shell_cmd": "gcc -Wall \"$file_name\" -o \"${file_base_name}.exe\" -llua && start cmd /c \"\"${file_path}/${file_base_name}.exe\" & pause\""
        }
    ]
}
复制代码

 

二、lua跟c之间的参数传递使用的是栈的方式:fifo

关于lua栈的操作方法有如下testStack里面用到的;

复制代码
void stackDump(lua_State* L) {
    int i;
    int top = lua_gettop(L);
    for (i = 1; i <= top; ++i) {
        int t = lua_type(L, i);
        switch(t) {
            case LUA_TSTRING: {
                printf("'%s'", lua_tostring(L, i));
                break;
            }
            case LUA_TBOOLEAN: {
                printf(lua_toboolean(L, i)?"true":"false");
                break;
            }
            case LUA_TNUMBER: {
                printf("%g", lua_tonumber(L, i));
                break;
            }
            default: {
                printf("%s", lua_typename(L, t));
                break;
            }
        }
        printf(" ");
    }
    printf("\n");
}

void TestStack(lua_State* L) {
    lua_pushboolean(L, 1);
    lua_pushnumber(L, 10);
    lua_pushnil(L);
    lua_pushstring(L, "hello");
    stackDump(L);

    lua_pushvalue(L, -4); // 插入从栈顶往下数第四个对应的那个值
    stackDump(L);

    lua_replace(L, 3); // 将栈顶的值取出,替换从栈底往上数第三个的值
    stackDump(L);

    lua_settop(L, 6); // 将栈的大小设置为6;如果之前栈大于6,则变成6;如果之前栈小于6,则新增的栈的位置赋nil
    stackDump(L);

    lua_remove(L, -3); // 移除从栈顶往下数,第三个的栈值
    stackDump(L);

    // lua_settop(L, -5); // 相当于删除栈顶的5个元素
    lua_insert(L, -4); // 将栈顶的值取出插入到从栈顶往下数第四个的位置;则之后的三个值网上移。注意这个跟lua_replace的区别
    stackDump(L);
}
复制代码

 

三、查询元素

有lua_is*(lua_State* L, int index) 查询对应的是什么类型的元素 lua_isnumber,lua_isstring, lua_istable等

isnumber判断的是该值能否转成数字,不一定是数字。所以对于任何数字,isstring一定是返回真。

 

查看类型有另外一个函数:lua_type  返回该类型,他们用常量代替;

获取值的有lua_tostring,lua_tolstring, 查看源码可以发现

#define lua_tostring(L,i)    lua_tolstring(L, (i), NULL)

lua_tostring是一个宏;

返回的是const char* 类型的;第三个参数可以返回字符串的长度;如下所示

const char     *(lua_tolstring) (lua_State *L, int idx, size_t *len);

 

向查询当前栈中有多少个值,可以使用lua_gettop()函数

默认情况下lua的栈可以装20个值;如果任务比较多,可以使用

lua_checkstack这个函数来检查栈中是否有足够的空间。如果返回0则表示false,1则表示容纳的下。

 

三、调用lua自定义模块

void load(lua_State* L, const char* fname) {
    if (luaL_loadfile(L, fname) || lua_pcall(L,0,0,0))
        error(L, "cannot run cfg file: %s", lua_tostring(L,-1));
}

首先需要先将文件load进来;然后调用pcall;这两个函数如果调用没有问题则会返回0,如果出现错误则会返回对应的错误代码,并将错误代码压入栈顶。

上面的函数当loadfile完成之后再调用pcall;

手册中明确提到,lua_load把一个文件当作一个chunk编译后放到stack的栈顶;

chunk就是一个可执行语句的组合,可以是一个文件也可以是一个string;

“Lua handles a chunk as the body of an anonymous function with a variable number of arguments” 这是Lua对chunk也就是lua文件的处理方式,就是认为是一个可变参数的匿名函数。也就是说,调用后栈上有一个匿名函数,这个函数的body就是文件中所有的内容。

在luaL_loadfile后,调用lua_getop以及lua_type可以知道栈的大小为1,放在栈上的是一个fucntion类型的value。为什么loadfile后我们不能直接获取到printmsg这个函数呢,那是因为刚才提到的,loadfile仅仅视编译lua文件,并不执行这个文件,也就是说只是在栈上形成了一个匿名函数。只有执行这个函数一次,才会使得printmsg可以通过lua_getglobal获取,否则,全局变量是空的。

Lua在执行函数的时候,函数会实例化,获得的closure也是这个函数的最终值。
具体可以查看:https://blog.csdn.net/liutianshx2012/article/details/44034421/

四、关于table的操作

获取lua中的table的value

lua_getglobal(L, "background"); // 将lua的全局table background压入栈顶,再获取background 这个table表中的value,如下

复制代码
#define MAX_COLOR 255
int getfield(lua_State* L, const char* key) {
    int result;
    // lua_pushstring(L, key);
    // lua_gettable(L, -2); // 弹出栈顶的key,然后压入栈顶value
    lua_getfield(L, -1, key); // 上面注释的方式和当前的这种方式均能做到上述注释的操作。即栈顶为value
    if (!lua_isnumber(L, -1))
        error(L, "invalid color");
    result = (int)lua_tonumber(L, -1) * MAX_COLOR;
    lua_pop(L, 1); // 弹出栈顶的1个元素;如果为n,则为弹出n个元素,这里要注意如果是字符串的话,得先拷贝一份再弹出,因为弹出之后字符串内存被释放
    return result;
}
复制代码

如下则是设置table的操作

复制代码
void setfield(lua_State* L, const char* key, int val) { // 设置table中的key跟val
    lua_pushstring(L, key);
    lua_pushnumber(L, (double)val/MAX_COLOR);
    lua_settable(L, -3);// 设置进table之后,栈顶的两个值会被弹出
}

void setcolor(lua_State* L, struct ColorTable* ct) {
    printf("%d", lua_gettop(L));
    lua_newtable(L); // 压入栈顶,从gettop的个数可以看出
    printf("%d", lua_gettop(L));
    setfield(L, "r", ct->red);
    setfield(L, "g", ct->green);
    setfield(L, "b", ct->blue);
    lua_setglobal(L, ct->name); // 必须最后设置,因为该操作为:出栈弹出table,并设置table名字;即将table为name设置为lua中的global
    printf("%d", lua_gettop(L));
}
复制代码

五、调用lua中的函数

func.txt

function f(x, y)
    return (x^2 * math.sin(y)) / (1-x)
end

C代码

复制代码
void LoadFunc(lua_State* L) {
    if (luaL_loadfile(L, "func.txt") || lua_pcall(L, 0, 0, 0))
        error(L, "load func.txt error");
}

double f(lua_State* L, double x, double y) {
    double z;
    lua_getglobal(L, "f"); // 将lua全局的名字为f的压入栈
    lua_pushnumber(L, x);  // 依次将x跟y压入栈中
    lua_pushnumber(L, y);
    if (lua_pcall(L, 2, 1, 0) != 0) //2是指两个参数,1是指要获取1个返回值;如果有n个,则可以设置为n;假设返回值为a,b,c;他们对应的栈为-3,-2,-1
        error(L, "error 'f' %s", lua_tostring(L, -1)); //pcall 的最后一个参数如果不为0,则当发生错误时候会调用栈中对应的参数值
    if (!lua_isnumber(L, -1))
        error(L, "func f must return anumber");
    z = lua_tonumber(L, -1);
    lua_pop(L, 1);
    return z;
}
复制代码

 

posted @   LCAC  阅读(298)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示