user1598585
user1598585

Reputation:

Getting a “pointer” to a Lua function stored in C

In the Lua C API I can store a number or a string from the stack with lua_tostring().

How can a “reference” (if that is the correct term) to a Lua function be passed to C through the Lua API? So it can be called later from C, with lua_call(), without having to reference it by its name.

(It really needs to be like that, the C program will call the function somewhere in the future and the program doesn't know anything about the function because the functions to be passed are defined in the Lua program)

Upvotes: 2

Views: 5633

Answers (1)

Niccolo M.
Niccolo M.

Reputation: 3413

In C you can't refer to Lua functions directly but you can represent numbers and strings. So, for a function to "be called later", you can store this function in some table and refer to it by a numeric or string key of the table.

Here's a simpleminded mechanism to start with:

On the Lua side:

funcs = {}

local function register_hanlder(key, fn)
  funcs[key] = fn
end

register_handler("on_mouse_click", function()
  print "You clicked me!"
end)

On the C side:

/* code not tested */
lua_getglobal(L, "funcs");
lua_getfield(L, -1, "on_mouse_click");
if (!lua_isnil(L, -1)) {
  lua_call(L, 0, 0);
else {
  // nothing registered
}

Instead of registering the functions in a global table you can register them in the registry table (see luaL_ref). You'll get some integer (that's the key in the registry table where the function value is) that you can pass around in you C code.

Note that if you don't need to store a Lua function "for use later" you don't need any of this: if your C function has some Lua function passed to it via argument you can call it outright.

== Edit:

As I mentioned, instead of using a global variable (the funcs above) you can store the reference to the function in the "registry". Conceptually there's no difference between this method and the previous one.

Let's re-use the previous example: you want the Lua programmer to be able to register a function that would be fired whenever a mouse is clicked in your application.

The Lua side would look like this:

register_mouse_click_handler(function()
  print "the mouse was clicked!"
end)

On the C side you define register_mouse_click_handler:

static int the_mouse_click_handler = 0;

static int register_mouse_click_handler(lua_State* L) {
  the_mouse_click_handler = luaL_ref(L, LUA_REGISTRYINDEX);
  return 0;
}

(...and expose it to Lua.)

Then, in your application, when the mouse is clicked and you want to call the Lua function, you do:

...
if (the_mouse_click_handler != 0) {
  lua_rawgeti(L, LUA_REGISTRYINDEX, the_mouse_click_handler);
  lua_call(L, 0, 0);
} else {
  // No mouse handler was registered.
}
...

(I may have typos in the code.)

Upvotes: 3

Related Questions