前文须知
Lua的VS安装参考此文:
本文会通过一些示例展示如何用lua调用C/C 传递过来的函数,并辅以部分解释语句:
Lua中调用C/C 函数简介:
- 任何在Lua中注册的C函数必须有同样的原型, typedef int (lua_CFunction) (lua_State L); 其定义在"lua.h"中。 被注册的C函数接收一个单一的lua_State类型的参数,同时返回一个表示返回值个数的数字。
- 而Lua利用一个虚拟的堆栈来给C传递值或从C获取值。每当Lua调用C函数,都会获得一个新的堆栈,该堆栈初始包含所有的调用C函数所需要的参数值(Lua传给C函数的调用实参),并且C函数执行完毕后,会把返回值压入这个栈(Lua从中拿到C函数调用结果)。
- 对lua堆栈不太理解的可以去搜 Lua初学者(四)--Lua调用原理展示(lua的堆栈)这篇文章
c/c 注册函数给lua调用
C/C 注册函数给lua的方式有多种
- 使用
lua_register
通过 _G 表间接地将函数注册到全局环境中 lua_pushcfunction
到栈里再通过lua_setglobal
取出注册到_G表里或者通过- 使用
lua_rawsetfield
/lua_setfield
注册到特定的表里
1.函数注册到全局环境的方式
无参函数
代码语言:cpp复制#include <stdio.h>
#include <lua.hpp>
extern "C" {
// 一个Lua函数的标准模型
LUALIB_API int lua_TestFunc2(lua_State* L)
{
printf("lua调用C函数n");
// 表示有0个返回值
return 0;
}
}
int main()
{
// 创建一个虚拟机
lua_State* L = luaL_newstate();
// 加载一些常用的系统库
luaL_openlibs(L);
// 注册一个函数给lua 以k v 的形式注册
lua_register(L, "testFunc", lua_TestFunc2);
/* 因为其宏定义为
* #define lua_register(L,n,f)
* (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
* 所以等价于
* 向栈中压入一个函数至栈顶
* lua_pushcfunction(L, lua_TestFunc);
* 将栈顶的名称元素设置名称为testFunc 在lua中可以范围该名称
* lua_setglobal(L, "testFunc");
*/
// 加载lua文件并执行
luaL_dofile(L, "Test2.lua");
// 关闭虚拟机
lua_close(L);
return 0;
}
代码语言:lua复制-- Test2.lua
print("Lua_Hello World!")
testFunc()
- 对于LUALIB_API 这是一个为了确保函数能够被正确地导出并在 Lua 中调用的宏
- extern "C"是为了确保以C的编译器去编译,避免C 的编译器导致的错误,毕竟lua是纯C的
- 一般要暴露给lua的函数都可以如上标注以防奇怪的错误。
有参函数的注册互动
代码语言:cpp复制#include <stdio.h>
#include <lua.hpp>
extern "C" {
// 一个Lua函数的标准模型
LUALIB_API int lua_TestFunc3(lua_State* L)
{
// 获取有几个参数
int top = lua_gettop(L);
printf("传入几个参数 top:[%d]n", top);
// 下标从1开始 检查第一个参数是否为整型,是则返回整型
int num1 = luaL_checkinteger(L, 1);
int num2 = luaL_checkinteger(L, 2);
int num3 = luaL_checkinteger(L, 3);
printf("从栈底由下到上开始取数据:%d %d %dn", num1,num2,num3);
int num4 = luaL_checkinteger(L, -1);
int num5 = luaL_checkinteger(L, -2);
int num6 = luaL_checkinteger(L, -3);
printf("从栈顶由上到下开始取数据:%d %d %dn", num4, num5, num6);
lua_pushinteger(L, 999);// 压入第一个参数 整型
lua_pushstring(L, "hello World!!!!!");// 压入地二个参数 字符串
// 表示有2个返回值
return 2;
}
}
int main()
{
// 创建一个虚拟机
lua_State* L = luaL_newstate();
// 加载一些常用的系统库
luaL_openlibs(L);
// 注册一个函数给lua全局环境
lua_register(L, "testFunc", lua_TestFunc3);
// 加载lua文件并执行
if (luaL_dofile(L, "Test3.lua"))
{
// 在lua中 -1表示栈顶 如果出错 出错结果会放置在栈顶中
printf("%sn", lua_tostring(L, -1));
}
// 关闭虚拟机
lua_close(L);
return 0;
}
通过从lua的栈里取出数据作为函数的参数使用
在push数据到lua的栈里后,需要函数的返回值告诉lua有几个返回值
Tips:
- 正数索引是从栈底开始计数的,索引 1 表示栈底的第一个元素(即最先进入栈的元素),索引 2 表示栈底的第二个元素,依此类推。
- 负数索引是从栈顶开始计数的,索引 -1 表示栈顶的元素(即最近进入栈的元素),索引 -2 表示栈顶之前的元素,依此类推。
通常建议使用负数索引