目录
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)