C语言模块回调Lua函数的两种方法_Lua

lua和C通过虚拟栈这种交互方式简单而又可靠,缺点就是C做栈平衡稍微会多写一点代码。 今天分享学到的C模块回调Lua函数的两种方法,都是炒冷饭,大侠勿喷。

1. C保存函数对象

C模块可以通过注册表保存Lua里面的对象,等适当时候取出再调用即可。

复制代码 代码如下:

static int lua_callback = LUA_REFNIL;

static int setnotify(lua_State *L)
{
  lua_callback = luaL_ref(L, LUA_REGISTRYINDEX);
  return 0;
}

static int testnotify(lua_State *L)
{
  lua_rawgeti(L, LUA_REGISTRYINDEX, lua_callback);
  lua_call(L, 0, 0);
}

luaL_ref把栈顶的值取出,放到指定的tabel中,然后返回一个索引(目测是数组的index)。 lua_rawgeti把之前保存的function对象取出,再由lua_call调用。

复制代码 代码如下:

function callback(  )
    print "Callback"
end

cb.setnotify(callback)
cb.testnotify()

2. C访问Lua全局环境
第二种方法更简便,C直接调用Lua中的函数,就像Lua调用C一样

复制代码 代码如下:

static int testenv(lua_State *L)
{
  lua_getglobal(L, "defcallback");
  lua_call(L, 0, 0);
}

该方法的缺点就是如果C模块独立编写,方法名就不太灵活。 用这种方法一般会在Lua端再封装一层,以隔离全局环境。

3. 完整例子
cb.c

复制代码 代码如下:

#include <stdio.h>
#include <stdlib.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

static int lua_callback = LUA_REFNIL;

static int setnotify(lua_State *L)
{
  lua_callback = luaL_ref(L, LUA_REGISTRYINDEX);
  return 0;
}

static int testnotify(lua_State *L)
{
  lua_rawgeti(L, LUA_REGISTRYINDEX, lua_callback);
  lua_call(L, 0, 0);
}

static int testenv(lua_State *L)
{
  lua_getglobal(L, "defcallback");
  lua_call(L, 0, 0);
}

static const luaL_Reg cblib[] = {
  {"setnotify", setnotify},
  {"testnotify", testnotify},
  {"testenv", testenv},
  {NULL, NULL}
};

int luaopen_cb(lua_State *L)
{
  luaL_register(L, "cb", cblib);
  return 1;
}

test.lua

复制代码 代码如下:

require("cb")

function callback(  )
  print "Callback"
end

function defcallback()
  print "Predef callback"
end

cb.setnotify(callback)
cb.testnotify()
print "Done"
cb.testenv()

时间: 2024-08-03 11:15:38

C语言模块回调Lua函数的两种方法_Lua的相关文章

C语言实现返回字符串函数的四种方法_C 语言

前言 C语言返回字符串函数共有四种方式,分别如下:       使用堆空间,返回申请的堆地址,注意释放       函数参数传递指针,返回该指针       返回函数内定义的静态变量(共享)       返回全局变量 下面来看看详细的介绍 其实就是要返回一个有效的指针,尾部变量退出后就无效了. 使用分配的内存,地址是有效 char *fun() { char* s = (char*)calloc(100, sizeof(char*) ); if (s) strcpy ( s , "abc &qu

Javascript中实现trim()函数的两种方法_javascript技巧

在JavaScript中我们需要用到trim的地方很多,但是JavaScript又没有独立的trim函数或者方法可以使用,所以我们需要自己写个trim函数来实现我们的目的. 方案一: 以原型方式调用,即obj.trim()形式,此方式简单且使用方面广泛,定义方式如下: 复制代码 代码如下: <script language="javascript"> /** * 删除左右两端的空格 */ String.prototype.trim=function() {      ret

php fseek函数读取大文件两种方法_php实例

php读取大文件,使用fseek函数是最为普遍的方式,它不需要将文件的内容全部读入内存,而是直接通过指针来操作,所以效率是相当高效的.在使用fseek来对文件进行操作时,也有多种不同的方法,效率可能也是略有差别的,下面是常用的两种方法. 方法一: 首先通过fseek找到文件的最后一位EOF,然后找最后一行的起始位置,取这一行的数据,再找次一行的起始位置,再取这一行的位置,依次类推,直到找到了$num行.实现代码如下: 整个代码执行完成耗时 0.0095 (s) function tail($fp

分析MS SQL Server里函数的两种用法

server|函数 SQL Server里函数的两种用法(可以代替游标) 1. 因为update里不能用存储过程,然而要根据更新表的某些字段还要进行计算.我们常常采用游标的方法,这里用函数的方法实现. 函数部分: 以下是引用片段: CREATE FUNCTION [DBO].[FUN_GETTIME] (@TASKPHASEID INT) RETURNS FLOAT AS BEGIN DECLARE @TASKID INT, @HOUR FLOAT, @PERCENT FLOAT, @RETUR

SQL Server里函数的两种用法(可以代替游标)

server|函数|游标 SQL Server里函数的两种用法(可以代替游标)1. 因为update里不能用存储过程,然而要根据更新表的某些字段还要进行计算.我们常常采用游标的方法,这里用函数的方法实现. 函数部分:CREATE FUNCTION [DBO].[FUN_GETTIME] (@TASKPHASEID INT) RETURNS FLOAT AS BEGIN   DECLARE @TASKID INT,          @HOUR FLOAT,           @PERCENT

SQL Server里函数的两种用法

SQL Server里函数的两种用法(可以代替游标) 1. 因为update里不能用存储过程,然而要根据更新表的某些字段还要进行计算.我们常常采用游标的方法,这里用函数的方法实现. 函数部分: 以下是引用片段: CREATE FUNCTION [DBO].[FUN_GETTIME] (@TASKPHASEID INT) RETURNS FLOAT AS BEGIN DECLARE @TASKID INT, @HOUR FLOAT, @PERCENT FLOAT, @RETURN FLOAT IF

c++连接mysql数据库的两种方法(ADO连接和mysql api连接)_C 语言

第一种方法可以实现我当前的需求,通过连接不同的字符串来连接不同的数据库.暂时只连接了mysql,sqlserver,oracle,access.对于access,因为它创建表的SQL语句不太兼容标准SQL语句,需要做一些处理,这里暂时不说.第二种方法只能针对于mysql数据库的连接,不过用这种方法不用安装MyODBC服务器程序. 不管用哪种方法,首先需要安装Mysql数据库,安装方法请看"mysql安装及一些注意点".最好安装一个Navicat for mysql,方便操作mysql数

PHP中file_get_contents函数抓取https地址出错的解决方法(两种方法)_php实例

方法一: 在php中,抓取https的网站,提示如下的错误内容: Warning: file_get_contents() [function.file-get-contents]: failed to open stream: Invalid argument in I:Webmyphpa.php on line 16 打开php.ini文件找到 ;extension=php_openssl.dll ,去掉双引号";" ,重启web服务器即可. apache服务器的话,可以同时启用m

JavaScript中的函数的两种定义方式和函数变量赋值_基础知识

复制代码 代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <script type="text/javascript"> /*I总结: 1.函数名可以做变量使用,可以赋值,可以传值 2.函数名当参数,传递给另一个函数 */ //===========