lua_pushvalue 是拷贝还是引用行为

今天群里有个朋友提了个问题,lua_pushvalue 的时候,是复制的拷贝还是引用?

先上结论:只有 lua_Integerlua_Number 以及 booleans,是实实在在的拷贝了数据。

首先看下 lua 的 state 定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
struct lua_State {
CommonHeader;
unsigned short nci; /* number of items in 'ci' list */
lu_byte status;
StkId top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
const Instruction *oldpc; /* last pc traced */
StkId stack_last; /* last free slot in the stack */
StkId stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize;
int basehookcount;
int hookcount;
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
l_signalT hookmask;
lu_byte allowhook;
};

可以看到,stack 的 base 是一个 StkId,StkId 定义如下:

1
typedef TValue *StkId;  /* index to stack elements */

是一个指向栈上元素的 index。那么,我们找到 TValue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef union Value {
GCObject *gc; /* collectable objects */
void *p; /* light userdata */
int b; /* booleans */
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
} Value;


#define TValuefields Value value_; int tt_


typedef struct lua_TValue {
TValuefields;
} TValue;

可以看到 TValue 是一个 Value 类型以及一个 int tt_来组成的。这里的_tt 其实是一个表明元素类型的值,而元素的值是存储在 value_中的。

再看 Value 类型,里面包括了 Lua 中最基本的数据类型。里面非指针类型的只有 int, float 和 bool 类型。

在清楚了栈上数据的结构后,我们再分析下 lua_pushvalue 的操作。

1
2
3
4
5
6
7
8
9
10
11
12
LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L);
setobj2s(L, L->top, index2addr(L, idx));
api_incr_top(L);
lua_unlock(L);
}

#define setobj2s setobj

#define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); *io1 = *(obj2); \
(void)L; checkliveness(L,io1); }

我把相关代码一并贴出来了。index2addr 函数主要就是返回栈上位于 index 的 TValue。如此一来,其实是 TValue 复制了。所以这个值如果是依赖于指针比如 GCObject 的,那么就是复制的引用,否则,就是拷贝了一份。

lua_pushvalue 是拷贝还是引用行为

https://robinxb.com/posts/2017/lua_pushvalue_copy_or_ref/

作者

薯条

发布于

2017-03-02

更新于

2024-01-15

许可协议

评论