在 C 中访问从 Lua 传递的表,而不复制值

发布于 2024-12-19 07:02:29 字数 4053 浏览 0 评论 0原文

我想将一个表从Lua传递到C,然后访问C中的所有值,而不将值从Lua地址空间复制到C堆栈。有办法做到这一点吗?我想最小化值的副本。

我尝试使用 gettable() 但在这种情况下,该值被复制到堆栈顶部。因此正在生成一个副本。我不想要这个。还有其他办法吗??

这是我的 C 代码:-

#include <lua.h>                               /* Always include this */
#include <lauxlib.h>                           /* Always include this */
#include <lualib.h>                            /* Always include this */
#include <malloc.h>

#define EXCEPTION_IS_NUMBER (-2)    //Passed a custom error no. to be returned in 
                                    //case of error
#define SUCCESS (0)

static int iquicksort(lua_State *L) {
    int k,len=0;
    len=lua_tointeger(L,-2);        //-2 specifies second element from top of stack.
                                    //So I have passed 2 elements from Lua to C,  first
                                    //is size of table and second table. So when they 
                                    //are pushed to stack, the size is second element
                                    //from top.So here I am storing it in variable len.
    int *q;
    int *p=(int *)malloc(len*sizeof(int));
    q=p;
    for(k=1;k<=len;k++)
    {
            lua_pushinteger(L,k);    //if I want to access a[2], where a is my table 
                                     //and 2 is the index, then '2' needs to be at top
                                     //of the stack and I need to pass the location of
                                     //'a' in stack as second argument to gettable().
                                     //So here Address of table was at top, I pushed 
                                     //the index on top, now address is second element
                                     //from top. So I passed it as '-2' in gettable
                                     //below. What gettable() does is that it fetches 
                                     //and copies that value at stack top. So I can 
                                     //use it from there.
            lua_gettable(L,-2);
            if(lua_isnumber(L,-1))   //Checking top value replaced by fxn is number...
            {
                    *p++=lua_tointeger(L,-1);   //Storing the values in array
            }
            else
            {
                    lua_pushinteger(L,EXCEPTION_IS_NUMBER);
                    return 1;
            }
            lua_pop(L,1);
    }
    p=q;
    sort(p,0,len-1);
    for(k=1;k<=len;k++)   //This fxn changes the value at prescribed location of table.
                          //here I am changing the values at Table's location...
                          //i.e. storing the sorted values in table.....
    {
            lua_pushinteger(L,k);
            lua_pushinteger(L,*p++);
            lua_settable(L,-3);
    }
    lua_pushinteger(L,SUCCESS);
    return 1;
}

//Simple quicksort of values.....
void sort(int *arr, int left,int right){
    int i = left, j = right;
    int tmp;
    int pivot = arr[(left + right) / 2];

  /* partition */
    while (i <= j) {
            while (arr[i] < pivot)
                    i++;
            while (arr[j] > pivot)
                    j--;
            if (i <= j) {
                    tmp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = tmp;
                    i++;
                    j--;
            }
    };

  /* recursion */
    if (left < j)
            sort(arr, left, j);
    if (i < right)
            sort(arr, i, right);
}

int luaopen_power(lua_State *L){
    lua_register(L,"quicksort",iquicksort);
    return 0;
}

我通过使用以下命令编译该程序生成了一个共享库:-

gcc -Wall -shared -fPIC -o power.so -I/usr/local/include/lua5.1 -llua5.1 quicksort.c

这是调用它的 Lua 代码:-

require("power")
x={5,4,6,5,3,2,3,9}
print("Before quicksort call....")
t=quicksort(#x,x)
if t==0 then
        for i,v in ipairs(x) do print(i,v) end
else
        print(string.format("%s %d","Error occurred. Errorcode is:: ",t))
end

谢谢

I want to pass a table from Lua to C and then access all the values in C without copying the values from Lua address space to C stack. Is there a way of doing this?? I want to minimize the copy of values.

I tried using gettable() but in that case, the value is copied onto top of stack. So a copy is getting generated. I don't want this. Is there any other way??

Here is my C code:-

#include <lua.h>                               /* Always include this */
#include <lauxlib.h>                           /* Always include this */
#include <lualib.h>                            /* Always include this */
#include <malloc.h>

#define EXCEPTION_IS_NUMBER (-2)    //Passed a custom error no. to be returned in 
                                    //case of error
#define SUCCESS (0)

static int iquicksort(lua_State *L) {
    int k,len=0;
    len=lua_tointeger(L,-2);        //-2 specifies second element from top of stack.
                                    //So I have passed 2 elements from Lua to C,  first
                                    //is size of table and second table. So when they 
                                    //are pushed to stack, the size is second element
                                    //from top.So here I am storing it in variable len.
    int *q;
    int *p=(int *)malloc(len*sizeof(int));
    q=p;
    for(k=1;k<=len;k++)
    {
            lua_pushinteger(L,k);    //if I want to access a[2], where a is my table 
                                     //and 2 is the index, then '2' needs to be at top
                                     //of the stack and I need to pass the location of
                                     //'a' in stack as second argument to gettable().
                                     //So here Address of table was at top, I pushed 
                                     //the index on top, now address is second element
                                     //from top. So I passed it as '-2' in gettable
                                     //below. What gettable() does is that it fetches 
                                     //and copies that value at stack top. So I can 
                                     //use it from there.
            lua_gettable(L,-2);
            if(lua_isnumber(L,-1))   //Checking top value replaced by fxn is number...
            {
                    *p++=lua_tointeger(L,-1);   //Storing the values in array
            }
            else
            {
                    lua_pushinteger(L,EXCEPTION_IS_NUMBER);
                    return 1;
            }
            lua_pop(L,1);
    }
    p=q;
    sort(p,0,len-1);
    for(k=1;k<=len;k++)   //This fxn changes the value at prescribed location of table.
                          //here I am changing the values at Table's location...
                          //i.e. storing the sorted values in table.....
    {
            lua_pushinteger(L,k);
            lua_pushinteger(L,*p++);
            lua_settable(L,-3);
    }
    lua_pushinteger(L,SUCCESS);
    return 1;
}

//Simple quicksort of values.....
void sort(int *arr, int left,int right){
    int i = left, j = right;
    int tmp;
    int pivot = arr[(left + right) / 2];

  /* partition */
    while (i <= j) {
            while (arr[i] < pivot)
                    i++;
            while (arr[j] > pivot)
                    j--;
            if (i <= j) {
                    tmp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = tmp;
                    i++;
                    j--;
            }
    };

  /* recursion */
    if (left < j)
            sort(arr, left, j);
    if (i < right)
            sort(arr, i, right);
}

int luaopen_power(lua_State *L){
    lua_register(L,"quicksort",iquicksort);
    return 0;
}

I generated a shared library by compiling this program using the following command:-

gcc -Wall -shared -fPIC -o power.so -I/usr/local/include/lua5.1 -llua5.1 quicksort.c

Here is the Lua code for calling this:-

require("power")
x={5,4,6,5,3,2,3,9}
print("Before quicksort call....")
t=quicksort(#x,x)
if t==0 then
        for i,v in ipairs(x) do print(i,v) end
else
        print(string.format("%s %d","Error occurred. Errorcode is:: ",t))
end

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

原谅我要高飞 2024-12-26 07:02:29

Lua 的 C API 仅复制低级 C 类型,例如数字和布尔值。对于所有其他内容,包括字符串,它使用指向内部 Lua 数据的指针。

The C API for Lua only copies low-level C types, such as numbers and booleans. For all others, including strings, it uses pointers to internal Lua data.

柠檬色的秋千 2024-12-26 07:02:29

我不确定 gettable() 是否将值复制到 Lua 堆栈,我认为它复制了该值的引用或指针...(特别是当该值本身是一个表时,该表的内容不被复制)。

鉴于Lua可能会进行魔法处理,我相信你的答案是否定的。

Lua 是免费软件,您可以下载它并查看源代码。对于 lua-5.2.0-rc4lua_gettable 函数位于文件 src/lapi.c 中,

LUA_API void lua_gettable (lua_State *L, int idx) {
  StkId t;
  lua_lock(L);
  t = index2addr(L, idx);
  api_checkvalidindex(L, t);
  luaV_gettable(L, t, L->top - 1, L->top - 1);
  lua_unlock(L);
}

因此实际工作由 完成luaV_gettable 来自文件 src/lvm.c,所以

void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
  int loop;
  for (loop = 0; loop < MAXTAGLOOP; loop++) {
    const TValue *tm;
    if (ttistable(t)) {  /* `t' is a table? */
      Table *h = hvalue(t);
      const TValue *res = luaH_get(h, key); /* do a primitive get */
      if (!ttisnil(res) ||  /* result is not nil? */
          (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
        setobj2s(L, val, res);
        return;
      }
      /* else will try the tag method */
    }
    else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
      luaG_typeerror(L, t, "index");
    if (ttisfunction(tm)) {
      callTM(L, tm, t, key, val, 1);
      return;
    }
    t = tm;  /* else repeat with 'tm' */
  }
  luaG_runerror(L, "loop in gettable");
}

我认为答案是否定的。但是,您可以修补或增强代码。我不明白为什么这个问题让你烦恼。仅复制简单数据(非常快),除非发生魔法(而魔法即元表是 Lua 语义的重要组成部分);聚合数据内容不会被复制。

I'm not sure that gettable() copies the value to the Lua stack, I think it copies a reference or pointer of the value... (especially when that value is a table itself, that table 's content is not copied).

And given that Lua may do magic processing, I believe your answer is no.

Lua being free software you can download it and look in the source code. With lua-5.2.0-rc4 the lua_gettable function is in file src/lapi.c

LUA_API void lua_gettable (lua_State *L, int idx) {
  StkId t;
  lua_lock(L);
  t = index2addr(L, idx);
  api_checkvalidindex(L, t);
  luaV_gettable(L, t, L->top - 1, L->top - 1);
  lua_unlock(L);
}

so the actual work is done by luaV_gettable from file src/lvm.c which is

void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
  int loop;
  for (loop = 0; loop < MAXTAGLOOP; loop++) {
    const TValue *tm;
    if (ttistable(t)) {  /* `t' is a table? */
      Table *h = hvalue(t);
      const TValue *res = luaH_get(h, key); /* do a primitive get */
      if (!ttisnil(res) ||  /* result is not nil? */
          (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
        setobj2s(L, val, res);
        return;
      }
      /* else will try the tag method */
    }
    else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
      luaG_typeerror(L, t, "index");
    if (ttisfunction(tm)) {
      callTM(L, tm, t, key, val, 1);
      return;
    }
    t = tm;  /* else repeat with 'tm' */
  }
  luaG_runerror(L, "loop in gettable");
}

so I think the answer is no. However, you could patch or enhance the code. I don't understand why the question bothers you. Only simple data is copied (very quickly), unless magic occurs (and the magic i.e. metatable is an essential part of Lua semantics); aggregate data content is not copied.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文