简体   繁体   English

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

[英]Access Table passed from Lua in C without Copying the values

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. 我想将表从Lua传递到C,然后访问C中的所有值,而不将值从Lua地址空间复制到C堆栈。 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. 我尝试使用gettable(),但在那种情况下,该值被复制到堆栈的顶部。 So a copy is getting generated. 因此,正在生成一个副本。 I don't want this. 我不要这个 Is there any other way?? 还有其他办法吗?

Here is my C code:- 这是我的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;
}

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:- 这是用于调用此代码的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

Thanks 谢谢

The C API for Lua only copies low-level C types, such as numbers and booleans. Lua的C API仅复制低级C类型,例如数字和布尔值。 For all others, including strings, it uses pointers to internal Lua data. 对于所有其他字符串(包括字符串),它使用指向内部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). 我不确定gettable()将值复制到Lua堆栈中,我认为它会复制值的引用或指针...(尤其是当该值是表本身时,不会复制该表的内容) 。

And given that Lua may do magic processing, I believe your answer is no. 考虑到Lua可能会进行魔术处理,我相信您的回答是否定的。

Lua being free software you can download it and look in the source code . Lua是免费软件,您可以下载它并查看源代码 With lua-5.2.0-rc4 the lua_gettable function is in file src/lapi.c 对于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);
}

so the actual work is done by luaV_gettable from file src/lvm.c which is 因此实际工作是通过src/lvm.c文件中的luaV_gettable完成的

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 ie metatable is an essential part of Lua semantics); 除非发生魔术(魔术(即metatable是Lua语义的重要组成部分)),否则仅复制(非常快速)简单数据。 aggregate data content is not copied. 汇总数据内容未复制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM