在C中存储对lua函数的引用

2024-02-09

我有一个用 C++ 实现的基本事件处理程序。我的应用程序中还有一个嵌入式 Lua 解释器,我需要它与事件管理器交互。最终目标是能够拥有一个事件处理程序,在事件触发时同时执行 C++ 和 Lua 函数。

我的问题是我无法想出一种简单的方法来存储对 C++ 代码中 lua 函数的引用。我知道如何从c执行Lua函数(使用lua_getglobal and lua_pcall),但我更愿意存储对函数本身的引用,这样我就可以直接将 Lua 函数传递给registerListener

Note假设 userdata 将是可以接受的NULL对于所有 Lua 听众。

这是我的代码:

事件管理器.h

#include <string>
#include <map>
#include <vector>

using namespace std;

typedef void (*fptr)(const void* userdata, va_list args);
typedef pair<fptr, void*> Listener;
typedef map<string, vector<Listener> > CallbackMap;

class EventManager {
private:
    friend ostream& operator<<(ostream& out, const EventManager& r);

    CallbackMap callbacks;
    static EventManager* emInstance;
    EventManager() {
        callbacks = CallbackMap();
    }
    ~EventManager() {
    }
public:
    static EventManager* Instance();
    bool RegisterEvent(string const& name);
    void RegisterListener(string const &event_name, fptr callback,
            void* userdata);
    bool FireEvent(string name, ...);
};

inline ostream& operator<<(ostream& out, const EventManager& em) {
    return out << "EventManager: " << em.callbacks.size() << " registered event"
            << (em.callbacks.size() == 1 ? "" : "s");
}

事件管理器.cpp

#include <cstdarg>
#include <iostream>
#include <string>

#include "EventManager.h"

using namespace std;

EventManager* EventManager::emInstance = NULL;

EventManager* EventManager::Instance() {
    if (!emInstance) {
        emInstance = new EventManager;
    }

    return emInstance;
}

bool EventManager::RegisterEvent(string const& name) {
    if (!callbacks.count(name)) {
        callbacks[name] = vector<Listener>();
        return true;
    }

    return false;
}

void EventManager::RegisterListener(string const &event_name, fptr callback,
        void* userdata) {
    RegisterEvent(event_name);
    callbacks[event_name].push_back(Listener(callback, userdata));
}

bool EventManager::FireEvent(string name, ...) {
    map<string, vector<Listener> >::iterator event_callbacks =
            callbacks.find(name);
    if (event_callbacks == callbacks.end()) {
        return false;
    }

    for (vector<Listener>::iterator cb =
            event_callbacks->second.begin();
            cb != event_callbacks->second.end(); ++cb) {
        va_list args;
        va_start(args, NULL);
        (*cb->first)(cb->second, args);
        va_end(args);
    }

    return true;
}

luaw_eventmanager.h

#pragma once
#ifndef LUAW_EVENT_H
#define LUAW_EVENT_H

#include "EventManager.h"

extern "C" {

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

void luaw_eventmanager_push(lua_State* L, EventManager* em);
int luaopen_weventmanager(lua_State* L);

}
#endif

luaw_eventmanager.cpp

#include <assert.h>
#include <stdio.h>

#include <sstream>
#include <iostream>

#include "luaw_eventmanager.h"

using namespace std;

static int
luaw_eventmanager_registerevent(lua_State* L)
{
    int nargs = lua_gettop(L);
    if (nargs != 2) {
        return 0;
    }

    stringstream ss;
    ss << luaL_checkstring(L, 2);

    EventManager::Instance()->RegisterEvent(ss.str());
    return 1;
}

static int
luaw_eventmanager_registerlistener(lua_State* L)
{
    return 1;
}

static int
luaw_eventmanager_fireevent(lua_State* L)
{
    return 1;
}

static int
luaw_eventmanager_tostring(lua_State* L)
{
    stringstream ss;
    ss << *EventManager::Instance();
    lua_pushstring(L, &ss.str()[0]);
    return 1;
}

static const struct luaL_Reg luaw_eventmanager_m [] = {
    {"registerEvent", luaw_eventmanager_registerevent},
    {"registerListener", luaw_eventmanager_registerlistener},
    {"fireEvent", luaw_eventmanager_fireevent},
    {"__tostring", luaw_eventmanager_tostring},
    {NULL, NULL}
};

void 
luaw_eventmanager_push(lua_State* L, EventManager* em)
{
    EventManager** emUserdata = (EventManager**)lua_newuserdata(L, sizeof(EventManager*));
    *emUserdata = em;
    luaL_getmetatable(L, "WEAVE.mEventManager");
    lua_setmetatable(L, -2);
}

int 
luaopen_weventmanager(lua_State* L)
{
    luaL_newmetatable(L, "WEAVE.mEventManager");
    lua_pushvalue(L, -1);
    lua_setfield(L, -2, "__index");
    luaL_register(L, NULL, luaw_eventmanager_m);
    assert(!lua_isnil(L, -1));
    return 1;
}

所有 Lua 拥有的对象都会被垃圾收集。这包括函数。因此,即使你可以获得 Lua 函数的引用,Lua 仍然会own因此,每当 Lua 检测到它不再被引用时,它就会受到 GC 的影响。

外部代码不能拥有 Lua 引用。但外部代码可以storeLua 代码无法到达(因此无法破坏)的地方的引用:Lua 注册表。

Lua 注册表 http://www.lua.org/manual/5.1/manual.html#3.5是一个Lua表(位于堆栈伪索引处LUA_REGISTRYINDEX,因此可以从堆栈访问),而 Lua 代码无法(直接)访问。因此,它是您存储所需物品的安全场所。由于它是一个 Lua 表,因此您可以像任何其他 Lua 表一样操作它(添加值、键等)。

然而,注册表是全局的,如果您使用其他 C 模块,它们完全有可能开始破坏彼此的东西。因此,最好为每个模块选择一个特定的注册表项,并在该注册表项中构建一个表。

步骤1:初始化 C 接口代码时,创建一个表并将其粘贴到注册表中的已知键中。只是一张空桌子。

当 Lua 代码传递给您一个 Lua 函数作为回调时,从特殊键加载该表并将 Lua 函数粘贴在那里。当然,要做到这一点,您需要为每个注册函数提供一个唯一的密钥(将其存储为 Lua 函数的void*data),您稍后可以使用它来检索该函数。

Lua 有一个简单的机制来做到这一点:luaL_ref http://www.lua.org/manual/5.1/manual.html#luaL_ref。该函数将使用给定的表将对象注册到堆栈顶部。此注册过程保证为每个注册对象返回唯一的整数键(只要您不manually背后修改系统的表)。luaL_unref发布一个参考,allo

由于引用是整数键,因此您could只是从int to void*这就是数据。我可能会使用一个显式对象(mallocing an int),但您可以按照自己喜欢的方式存储它。

第二步:当注册一个Lua函数时,使用luaL_ref将其添加到步骤 1 中创建的注册表中。将此函数返回的密钥存储在void*注册函数的参数。

第三步:当需要调用该函数时,使用您存储在中的整数键void*参数来访问步骤 1 中创建的注册表。这将为您提供该函数,然后您可以使用常用的 Lua 方法调用该函数。

第四步:当你注销Lua函数时,使用luaL_unref释放该函数(这样就可以避免泄漏 Lua 的内存)。如果你malloced 内存来存储整数密钥,free在这里。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在C中存储对lua函数的引用 的相关文章

  • 使用Physics.Raycast 和Physics2D.Raycast 检测对象上的点击

    我的场景中有一个空的游戏对象 带有 2D 组件盒碰撞器 我将脚本附加到该游戏对象 void OnMouseDown Debug Log clic 但是当我点击我的游戏对象时 没有任何效果 你有什么想法 如何检测我的盒子碰撞器上的点击 使用光
  • 启动时出现 OData v4 错误:找不到段“Whatever”的资源

    我正在构建新的 v4 服务 一切进展顺利 直到我为新模型 实体添加了新控制器 并在启动站点进行测试运行时收到此错误 控制器似乎编码正确 就像其他控制器一样 控制器 CustomersOData 中的操作 GetFeed 上的路径模板 Cus
  • 如何为 C 分配的 numpy 数组注册析构函数?

    我想在 C C 中为 numpy 数组分配数字 并将它们作为 numpy 数组传递给 python 我可以做的PyArray SimpleNewFromData http docs scipy org doc numpy reference
  • 单元测试一起运行时失败,单独运行时通过

    所以我的单元测试遇到了一些问题 我不能只是将它们复制并粘贴到这里 但我会尽力而为 问题似乎是 如果我一项一项地运行测试 一切都会按预期进行 但如果我告诉它一起运行测试 则 1 5 将通过 TestMethod public void Obj
  • C++中的类查找结构体数组

    我正在尝试创建一个结构数组 它将输入字符串链接到类 如下所示 struct string command CommandPath cPath cPathLookup set an alarm AlarmCommandPath send an
  • 生成(非常)大的非重复整数序列而不进行预洗牌

    背景 我编写了一个简单的媒体客户端 服务器 我想生成一个不明显的时间值 随从客户端到服务器的每个命令一起发送 时间戳中将包含相当多的数据 纳秒分辨率 即使它不是真正准确 因为现代操作系统中计时器采样的限制 等 我想做的 在 Linux 上
  • 如何在 Linq 中获得左外连接?

    我的数据库中有两个表 如下所示 顾客 C ID city 1 Dhaka 2 New york 3 London 个人信息 P ID C ID Field value 1 1 First Name Nasir 2 1 Last Name U
  • 单击 form2 上的按钮触发 form 1 中的方法

    我对 Windows 窗体很陌生 我想知道是否可以通过单击表单 2 中的按钮来触发表单 1 中的方法 我的表格 1 有一个组合框 我的 Form 2 有一个 保存 按钮 我想要实现的是 当用户单击表单 2 中的 保存 时 我需要检查表单 1
  • 在一个字节中存储 4 个不同的值

    我有一个任务要做 但我不知道从哪里开始 我不期待也绝对不想要代码中的答案 我想要一些关于该怎么做的指导 因为我感到有点失落 将变量打包和解包到一个字节中 您需要在一个字节中存储 4 个不同的值 这些值为 NAME RANGE BITS en
  • C++:.bmp 到文件中的字节数组

    是的 我已经解决了与此相关的其他问题 但我发现它们没有太大帮助 他们提供了一些帮助 但我仍然有点困惑 所以这是我需要做的 我们有一个 132x65 的屏幕 我有一个 132x65 的 bmp 我想遍历 bmp 并将其分成小的 1x8 列以获
  • 如何编写一个同时需要请求和响应Dtos的ServiceStack插件

    我需要提供本地化数据服务 所有本地化的响应 Dto 都共享相同的属性 IE 我定义了一个接口 ILocalizedDto 来标记那些 Dto 在请求端 有一个ILocalizedRequest对于需要本地化的请求 Using IPlugin
  • 私有模板函数

    我有一堂课 C h class C private template
  • .NET中的LinkedList是循环链表吗?

    我需要一个循环链表 所以我想知道是否LinkedList是循环链表吗 每当您想要移动列表中的 下一个 块时 以循环方式使用它的快速解决方案 current current Next current List First 电流在哪里Linke
  • C++ 密码屏蔽

    我正在编写一个代码来接收密码输入 下面是我的代码 程序运行良好 但问题是除了数字和字母字符之外的其他键也被读取 例如删除 插入等 我知道如何避免它吗 特q string pw char c while c 13 Loop until Ent
  • 用于 C# 的 TripleDES IV?

    所以当我说这样的话 TripleDES tripledes TripleDES Create Rfc2898DeriveBytes pdb new Rfc2898DeriveBytes password plain tripledes Ke
  • 有没有办法强制显示工具提示?

    我有一个验证字段的方法 如果无法验证 该字段将被清除并标记为红色 我还希望在框上方弹出一个工具提示 并向用户显示该值无效的消息 有没有办法做到这一点 并且可以控制工具提示显示的时间 我怎样才能让它自己弹出而不是鼠标悬停时弹出 If the
  • 编译时“strlen()”有效吗?

    有时需要将字符串的长度与常量进行比较 例如 if line length gt 2 Do something 但我试图避免在代码中使用 魔法 常量 通常我使用这样的代码 if line length gt strlen Do somethi
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • 如何使用 Word Automation 获取页面范围

    如何使用办公自动化找到 Microsoft Word 中第 n 页的范围 似乎没有 getPageRange n 函数 并且不清楚它们是如何划分的 这就是您从 VBA 执行此操作的方法 转换为 Matlab COM 调用应该相当简单 Pub
  • 在客户端系统中安装后桌面应用程序无法打开

    我目前正在使用 Visual Studio 2017 和 4 6 1 net 框架 我为桌面应用程序创建了安装文件 安装程序在我的系统中完美安装并运行 问题是安装程序在其他计算机上成功安装 但应用程序无法打开 edit 在客户端系统中下载了

随机推荐

  • VB6:扩展组合框中的项目数量

    有没有办法在 VB6 组合固有控件下拉时扩展其中出现的项目数量 我有大约 10 件物品 我想把它们全部展示出来 Karl Peterson 的经典 VB 网站上的这段代码将自动调整组合框的大小以匹配元素的数量 http vb mvps or
  • 我如何在没有看到合并的情况下进行责备

    如果我有一个历史记录如下的文件 A B C D E 我对 E 进行了责备 然后我想看看修订版 B 和 C 中发生了什么变化 但我并不真正关心 D 因为那是合并 我有办法做到这一点吗 我想我正在寻找某种 no merges 选项来 gitbl
  • 如何从 YouTube 频道 ID 获取用户的 Google+ ID

    我正在运行一项服务 人们可以使用 oauth 2 0 连接他们的 Google 帐户 并且通过 YouTube 权限 我可以管理他们的频道 访问他们的 YouTube 频道 ID 然而 我的问题是你是否可以倒退 即如何根据给定的 YouTu
  • 添加设备,在 genymotion 中出现 http 403 错误

    我有下载Genymotion 2 7 2 最新 形成侧面并安装在我的笔记本电脑中 我已经登录 添加任何设备时 它会给出以下错误 无法创建虚拟设备 服务器返回 HTTP 状态代码 403 None
  • 如何检测 Rails 3 路由中的整数?

    我想做一个littleroutes rb 中的一些额外逻辑可能不属于那里 但对我来说似乎最有意义 我有两条相互冲突的路线 说得原始一些 match videos browseby gt videos browse as gt browse
  • 如何在 Tomcat 中通过 JNDI 配置 JSF 2.0 应用程序的项目阶段

    一直在努力寻找一种配置 Tomcat 7 0 11 的方法 以便我的 Web 应用程序可以使用 Tomcat 配置中的项目阶段设置 到目前为止 没有运气 这个想法是在 Tomcat 服务器 主机 应用程序范围内设置此属性 但不在 web x
  • 周视图标题的全日历格式

    这些天我正在使用全日历 我想更改周视图中日期的格式 我发现很多人都成功使用了columnFormat month ddd week ddd d M day dddd d M 但这对我不起作用 也许原因是我使用西班牙语作为语言 这是我的日历代
  • 在 C# 中使用 twain 获取图像作为图像类

    我可以连接并从我的设备获取图像吐温网 http www codeproject com KB dotnet twaindotnet aspx 但我想将图像处理为Image班级 当我尝试这样的事情时 ArrayList pics tw Tra
  • Java:用于匹配引号之间的单词的正则表达式

    我有以下测试字符串 This is my te st case with lines for tes t ing with regex But as he said It could be an arbitrary number of wo
  • 让 SSL 与 OSX 上的 Apache/Passenger 一起使用

    我在我的开发机器上使用 apache passenger 但需要添加 SSL 支持 不通过控制面板公开的东西 我之前在生产中已经这样做过 但由于某种原因 我似乎无法在 OSX 上运行它 到目前为止我所遵循的步骤来自默认的 apache os
  • 转换 data.table 中的*一些*列类

    我想将 data table 列的子集转换为新类 这里有一个热门问题 转换 data table 中的列类 https stackoverflow com questions 7813578 convert column classes i
  • 如何将 asyncio 与其他操作系统线程同步?

    我有一个带有一个主线程的程序 我在其中生成第二个使用 asyncio 的线程 是否提供任何工具来同步这两个线程 如果一切都是异步的 我可以使用它的同步原语来完成 例如 import asyncio async def taskA lst e
  • VB.NET - 将 WinForm 应用程序导出/转换为 Web ASP.NET 应用程序的最简单方法

    背景 我有一个用 VB NET 编写的 winform 应用程序 它使用 WebService 根据用户选择进行不同采访的营销公司向用户发送不同的邀请 winform 应用程序从各种文本框 列表框和下拉列表中提取字符串值 以创建一些 XML
  • 在 Rails 应用程序中连接到 Google Analytics API [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否有一个很好的教程 如何在 Rails 应用程序中与 Google Analytics API 交互
  • 将任何base64文件转换为文件并移动到php / Symfony 4中的目标路径

    预先感谢我正在创建 APIsymfony 4只是上传base64 image或通过任何文件POSTMAN我必须将文件移动到目标目录 我在控制器中编写了以下代码 通过控制器我试图将文件移动到目录 但是 我收到的错误如下 未捕获的警告 file
  • 如何阻止 IE7 由于 hasLayout 清除浮动

    我有一个包含元素 其中包含许多浮动元素 该包含元素还应用了百分比宽度值 在 IE7 中 包含浮动的元素后面的内容被清除 因为宽度值赋予了它 hasLayout 我认为 我不希望包含元素具有布局 但我确实需要它具有明确的宽度 有没有办法在 I
  • 在 bitbucket ssh 连接期间,Linux 终端上出现“错误的配置选项”。

    我想开始使用 bitbucket 我已经按照教程的步骤连接到他们的服务器 link https confluence atlassian com pages viewpage action pageId 270827678 配置文件总是有问
  • Sparklyr - 更改 Spark 中的日期格式

    我有一个 Spark 数据框 其中有一列characters作为 20 01 2000 日 月 年 但我试图将其更改为日期格式 这样我就可以使用这里的功能 https cwiki apache org confluence display
  • 计算两个列表中匹配元素的数量

    我有 2 个包含随机数量元素的列表 例如 A 1 2 4 5 和 B 1 2 3 结果应该是2 我尝试过的代码 domains Numbers1 integer Numbers2 integer int list integer predi
  • 在C中存储对lua函数的引用

    我有一个用 C 实现的基本事件处理程序 我的应用程序中还有一个嵌入式 Lua 解释器 我需要它与事件管理器交互 最终目标是能够拥有一个事件处理程序 在事件触发时同时执行 C 和 Lua 函数 我的问题是我无法想出一种简单的方法来存储对 C