目录

C虚拟栈技术

压入元素

查询元素

其他栈操作

lua_is*函数

lua_to*函数从栈中获取一个值

练习

C调用Lua的函数、全局变量

Lua调用C的函数


C虚拟栈技术
Lua和C语言通信一个技术。几乎所有的API调用都会操作这个栈上的值。
压入元素
void lua_pushnil(lua_State *L);
void lua_pushboolean(lua_State *L,int bool);
void lua_pushnumber(lua_State *L, lua_Number n);
void lua_pushinteger(lua_State *L, lua_Integer);
void lua_pushlstring(lua_State *L, const char *s, size_t len);
void lua_pushstring(lua_State *L, const char *s);
判断虚拟栈内是否有足够的空间
int lua_checkstack(lua_State *L, int sz);
查询元素
API使用索引来引用栈中的元素。第一个压入栈中的元素索引为1(栈底),第二个压入为2.用负数来访问栈中的元素,-1表示栈顶元素,-2表示栈顶下面的元素,以此类推
其他栈操作
int lua_gettop(lua_State *L);//返回栈顶索引,相当于求栈长度
void lua_settop(lua_State *L, int index);//将栈顶指定某个位置
void lua_pushvalue(lua_State *L, int index);//赋值index元素并压入栈
void lua_remove(lua_State *L, int index);//将index的元素删除
void lua_insert(lua_State *L, int index);//将栈顶元素插入到index位置,index之后的位置往栈上方移动一位
void lua_replace(lua_State *L, int index);//将栈顶元素替换index的元素
void lua_pop(lua_State *L, int n);//删除n个栈顶元素 
lua_is*函数
为了检查一个元素是否为特定的类型,API提供了lua_is*.lua_isnumber、lua_isstring、lua_istable等
int lua_is*(lua_State int index); --给定的索引值是,在L中的索引
​
实际上,lua_isnumber是检查值是否能转换为数字类型,lua_isstring也有同样的行为
lua_to*函数从栈中获取一个值
int lua_toboolean(lua_State *L, int index);
lua_Number lua_tonumber(lua_State *L, int index);  --index为负数时,就是出栈?
lua_Integer lua_tointeger(lua_State *L, int index);
const char *lua_tolstring(lua_State *L, int index, size_t *len);
size_t lua_objlen(lua_State *L, int index);
​
lua_tolstring函数返回的是指向内部字符串副本的指针,并且不能修改。当对应的字符还在Lua的栈内,那么这个指针就会一直有效。当Lua调用一个C函数返回时,Lua就会清空它的栈。这就形成了一条规则,不要在函数之外使用在C函数内获得指向Lua字符串的指针
​
lua_lstring返回的字符串在其末尾都会有一个额外的零。字符串长度会在函数第三个参数返回。
练习

功能:由下而上打印栈内元素

【main.cpp】

#include<stdio.h>
​
extern "C"
{
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
}
lua_State *L;
​
static void stackDump()
{
    int lens = lua_gettop(L);
    for(int i = 1; i <= lens; ++i){
        int type = lua_type(L, i);
        switch(type)
        {
            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, i));
            }
        }
        printf("\n");
    }
}
​
void run()
{
    lua_getglobal(L, "width");
    lua_getglobal(L, "length");
    lua_getglobal(L, "height");
​
    stackDump();
}
​
int main()
{
    L = luaL_newstate();
    luaL_openlibs(L);
    luaL_dofile(L, "add.lua");
    run();
}
【add.lua】
width = 7
length = 8
height = 9
​
function add(x, y)
    -- print("x:",x,"y:",y)
    return x + y
end

C调用Lua的函数、全局变量

步骤:

1、函数入栈,参数按正序入栈

2、void lua_call(lua_State,*L int nargs, int results)//nargs是参数的个数,results是返回的数量   会从栈中取出元素

3、从栈顶取出函数进行运算,将结果压入栈中

4、以上操作会把参数、函数本身出栈

通过lua_getglobal函数获取Lua的函数名、全局变量

通过虚拟栈进行数据交换

【main.cpp】

#include<bits/stdc++.h>
using namespace std;
extern "C"
{
    #include "lua.hpp"
    #include "lualib.h"
    #include "lauxlib.h"
}

lua_State *L;

int add(int x, int y)
{
    lua_getglobal(L, "add");//调用函数的步骤,放入函数,参数按序放入,然后调用lua_call
    lua_pushnumber(L, x);
    lua_pushnumber(L, y);
    lua_call(L, 2, 1); //栈取出栈2个参数、1个返回值入栈

    int sum = lua_tonumber(L, - 1);

    lua_getglobal(L, "width");
    lua_getglobal(L, "height");
    lua_getglobal(L, "length");

    int lens = lua_gettop(L);
    printf("lens: %d\n", lens);
    for(int i = 1; i <= lens; ++i){
        int num = lua_tonumber(L, i);
        printf("num:%d\n", num);
    }
    return sum;
}

int main()
{
    L = luaL_newstate();
    luaL_openlibs(L);
    luaL_dofile(L, "add.lua");
    int sum = add(10, 20);
    printf("%d\n", sum);
    lua_close(L);
    return 0;
}

【add.lua】

width = 1
height = 2
length = 3

function add(x, y)
	return x + y
end
Lua调用C的函数

其实还是在C工程下运行,只不过注册函数到Lua中,Lua调用了C函数

比较精妙的一点是,C注册函数至Lua后,Lua调用这个函数时传递的参数个数是动态的,会全部放入只属于这个函数的虚拟栈内,C函数通过取出栈内元素进行操作。

操作后的答案继续放入栈中,并且返回一个整数,代表答案的个数,Lua内通过相同数量的全局变量即可获得所有答案

注册函数两种方法

方法1: lua_register(L, "addmethod", Addmethod);

方法2:

lua_pushcfunction(L, Addmethod);
 lua_setglobal(L, "addmethod");

【main.cpp】

#include<bits/stdc++.h>
using namespace std;

extern "C"
{
    #include "lua.hpp"
    #include "lualib.h"
    #include "lauxlib.h"
}

lua_State *L;

static int Addmethod(lua_State *t)
{
    int first = luaL_checknumber(t, 1);
    int second = luaL_checknumber(t, 2);
    lua_pushnumber(t, first + second);
    return 1;
}

static int Printmethod(lua_State *t)
{
    int answer = luaL_checknumber(t, 1);
    printf("answer:%d\n", answer);
    return 0;
}


int main()
{
    L = luaL_newstate();
    luaL_openlibs(L);
    
    lua_register(L, "addmethod", Addmethod);
    lua_register(L, "printmethod", Printmethod);

    luaL_dofile(L, "add.lua");


    lua_close(L);
    return 0;
}

【add.lua】

first = 10
second = 20
local ans = addmethod(10, 20)
printmethod(ans)