I want to store a pointer into the lua_State object, and retrieve that pointer in callbacks.
It's just the same, single pointer, in all callbacks. I think what I need is lightuserdata
, but I can't find complete examples on how to set and fetch the pointer.
I just need something this simple:
void SetPointer(lua_State* L, void* p) {
lua_pushlightuserdata (l, p);
// What else to do?
}
void GetPointer(lua_State* L) {
// How to get the lightuserdata?
}
I can do it either using the raw Lua API or using the Sol wrapper library [1]
Make sure that you really don't want to use full userdata (in most cases you want). Read e.g., PIL 28.5 - Light Userdata to get a better idea.
To use light userdata you need to manage its lifetime in C side and availability in Lua all on your own. To set and get light userdata on/from Lua stack use respectively: lua_pushlightuserdata
and lua_touserdata
(this function is shared with full userdata). You can also use lua_topointer
to read the pointer value; note that it has wider and slightly different use.
To allocate and make it available:
char* obj = malloc(2); // lifetime managed by C
obj[0] = 'U';
obj[1] = 0;
lua_pushlightuserdata(L, obj);
lua_setglobal(L, "ptr"); // make it available to Lua via global variable
Afterwards, you can use it in Lua:
print(ptr) --> userdata: 0x556be32ba2e0
another = ptr
And in C:
lua_getglobal(L, "another"); // another global from the previous sample
void* ref1 = lua_touserdata(L, -1);
printf("%p\n", ref1); //: 0x556be32ba2e0
const void* ref2 = lua_topointer(L, -1);
printf("%p\n", ref2); //: 0x556be32ba2e0
lua_pop(L, 1);
Finally, you will need to free the allocated object at the correct spot:
free(obj); // again, lifetime managed by C
Now, where is "the correct spot"? Well... It's where you would usually put it when writing in pure C: when you (or your user) no longer need it or never (e.g., if you like memory leaks, your program is short-lived or object lifetime is same as program lifetime).
As an alternative to global variable, you may put the pointer into the Registry. This will make it accessible to you via the Lua state in C but not from the Lua side:
char* obj; // initialize it as before
lua_pushstring(L, "myprogram_that_one_object"); // prefix your key, registry is shared with all libraries
lua_pushlightuserdata(L, obj);
lua_settable(L, LUA_REGISTRYINDEX);
Then, in possibly another scope, when you want to use or free it:
lua_pushstring(L, "myprogram_that_one_object");
lua_gettable(L, LUA_REGISTRYINDEX);
char* obj = lua_touserdata(L, -1);
free(obj); // or use it
lua_pop(L, 1);
If you use full userdata, Lua will manage the lifetime of the object for you (it will be garbage collected just like normal Lua values).