问题描述
我正在草绘一个小的C ++程序,该程序会将数组传递给Lua并在那里进行修改,我打算在其中读取lua脚本,以便无需重新编译程序就可以对其进行修改
我的第一个障碍是确保Lua能够修改已经分配的数组,而不是在Lua空间中再次分配它们。数据将是浮动的,并且大小将非常大,但是我现在从小开始。
为简化此界面,我尝试了LuaBridge 2.6,但未提供预期的结果。下面是一个完全“有效”的程序。
assignOneTrack()
请注意,没有任何匹配项。 Lua中output [10]的内容不是C ++空间中input [256]的值,而是input [0]。 C ++输出数组未在Lua中更新,cout表明它在我们初始化时保持不变(0)。 为了确认这一点,我们将output [10]的这个值压入了栈,在C ++中不是input [256],然后从C ++中检索到。 你们能纠正我还是指出我应该在哪里实现这一目标?
=======更新2020年8月11日=======
为弄清楚程序在做什么(或应该做什么),在阅读了Robert和Joseph的注意事项之后,我在C ++部分及其调用的lua脚本的更新版本下面发布了内容。注意,由于我第一次尝试没有成功,所以我放弃了LuaBridge:
C ++:
#include <iostream>
#include <cstdint>
#include <cstring>
#include <vector>
#include <lua5.3/lua.hpp>
#include <LuaBridge/LuaBridge.h>
int main(void)
{
const uint32_t LENGTH = 512 * 256;
std::vector <float> input(LENGTH),output(LENGTH);
memset(output.data(),LENGTH * sizeof(float)); // Zero the output
for(uint32_t i = 0; i < LENGTH; i++) // Populate input
input[i] = (float)i + 0.5f;
lua_State *luastate = luaL_newstate();
luabridge::push(luastate,input.data()); // Supposedly passing a pointer to the first element of input,according to LuaBridge manual chap 3-3.1
luabridge::push(luastate,output.data()); // Same for output
luaL_dostring(luastate,"output[10] = input[256]"); // Expecting to assign this value in the C++ arrays,not in the Lua space
lua_getglobal(luastate,"output[10]"); // Find this assigned value in the Lua stack
lua_Number val = lua_tonumber(luastate,1); // Retrieving this value from Lua to C++
std::cout << input[256] << "," << output[10] << "," << val << std::endl; // The values of val and in output[10] don't match
lua_close(luastate);
return 0;
}
Lua脚本如下:
#include <iostream>
#include <cstdint>
#include <cstring>
#include <vector>
#include <luajit-2.0/lua.hpp> // LuaJIT 2.0.4 from Ubuntu 16.04
int main(void)
{
const uint32_t LENGTH = 256 * 512;
std::vector <float> input(LENGTH),LENGTH * sizeof(float));
for(uint32_t i = 0; i < LENGTH; i++)
input[i] = (float)i + 0.5f;
lua_State *luastate = luaL_newstate();
luaL_openlibs(luastate);
// Here I have to pass &input[0],&output[0] and LENGTH
// to Lua,which in turn will pass to whatever functions
// are being called from a .so lib opened in Lua-side
luaL_dofile(luastate,"my_script.lua");
lua_close(luastate);
return 0;
}
解决方法
我正在草绘一个小的C ++程序,该程序会将数组传递给Lua
数据将是浮动的,并且大小将非常大,
我的建议:
- 将缓冲区保留在C侧(例如,作为全局变量)
- 将C函数暴露给LUA
GetTableValue(Index)
- 将C函数暴露给Lua
SetTableValue(Index,Value)
应该是这样的:
static int LUA_GetTableValue (lua_State *LuaState)
{
float Value;
/* lua_gettop returns the number of arguments */
if ((lua_gettop(LuaState) == 1) && (lua_isinteger(LuaState,-1)))
{
/* Get event string to execute (first parameter) */
Offset = lua_tointeger(LuaState,-1);
/* Get table value */
Value = LUA_FloatTable[Offset];
/* Push result to the stack */
lua_pushnumber(Value);
}
else
{
lua_pushnil(LuaState);
}
/* return 1 value */
return 1;
}
您还需要注册该功能:
lua_register(LuaState,"GetTableValue",LUA_GetTableValue);
我让你写SetTableValue
,但是它应该非常接近。
这样,缓冲区位于C端,可以使用专用功能从Lua
进行访问。
我建议您创建一个用户数据,以通过__index
和__newindex
公开数组,就像这样(像Lua一样,用C和C ++多种语言编写):
#include <stdio.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <lua5.3/lua.h>
#include <lua5.3/lauxlib.h>
#ifdef __cplusplus
}
#endif
struct MyNumbers {
lua_Number *arr;
lua_Integer len;
};
int MyNumbers_index(lua_State *L) {
struct MyNumbers *t = (struct MyNumbers *)luaL_checkudata(L,1,"MyNumbers");
lua_Integer k = luaL_checkinteger(L,2);
if(k >= 0 && k < t->len) {
lua_pushnumber(L,t->arr[k]);
} else {
lua_pushnil(L);
}
return 1;
}
int MyNumbers_newindex(lua_State *L) {
struct MyNumbers *t = (struct MyNumbers *)luaL_checkudata(L,2);
if(k >= 0 && k < t->len) {
t->arr[k] = luaL_checknumber(L,3);
return 0;
} else {
return luaL_argerror(L,2,lua_pushfstring(L,"index %d out of range",k));
}
}
struct MyNumbers *MyNumbers_new(lua_State *L,lua_Number *arr,lua_Integer len) {
struct MyNumbers *var = (struct MyNumbers *)lua_newuserdata(L,sizeof *var);
var->arr = arr;
var->len = len;
luaL_setmetatable(L,"MyNumbers");
return var;
}
int main(void) {
const lua_Integer LENGTH = 512 * 256;
lua_Number input[LENGTH],output[LENGTH];
memset(output,sizeof output);
for(lua_Integer i = 0; i < LENGTH; ++i)
input[i] = i + 0.5f;
lua_State *L = luaL_newstate();
luaL_newmetatable(L,"MyNumbers");
lua_pushcfunction(L,MyNumbers_index);
lua_setfield(L,-2,"__index");
lua_pushcfunction(L,MyNumbers_newindex);
lua_setfield(L,"__newindex");
/* exercise for the reader: implement __len and __pairs too,and maybe shift the indices so they're 1-based to Lua */
lua_pop(L,1);
MyNumbers_new(L,input,LENGTH);
lua_setglobal(L,"input");
MyNumbers_new(L,output,"output");
luaL_dostring(L,"output[10] = input[256]");
lua_getglobal(L,"output");
lua_geti(L,-1,10);
lua_Number val = lua_tonumber(L,-1);
printf("%f,%f,%f\n",input[256],output[10],val);
lua_close(L);
}
使用这种方法,Lua中没有任何数据的副本,而您自己的MyNumbers_
函数控制着如何完成对它们的所有访问。
如果您希望能够通过LuaJIT的FFI使用数组,而不是直接在Lua中操作它们,那么可以将它们的地址传递给一个简单的用户数据,如下所示:
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <luajit-2.0/lua.h>
#include <luajit-2.0/lualib.h>
#include <luajit-2.0/lauxlib.h>
#ifdef __cplusplus
}
#endif
int main(void) {
const lua_Integer LENGTH = 256 * 512;
lua_Number input[LENGTH],sizeof output);
for(lua_Integer i = 0; i < LENGTH; ++i)
input[i] = i + 0.5f;
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_pushlightuserdata(L,input);
lua_setglobal(L,"input");
lua_pushlightuserdata(L,output);
lua_setglobal(L,"output");
lua_pushinteger(L,"LENGTH");
luaL_dofile(L,"my_script.lua");
lua_close(L);
}