2

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)

2
  • Something like this? colberg.org/gcc-lua-cdecl/ffi-cdecl.html Commented May 22, 2014 at 4:38
  • Doesn't seem like what I want @RobertHarvey, if you know the relevant parts on how to do it, post them as an answer please. Commented May 22, 2014 at 4:42

1 Answer 1

3

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.)

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your reply but sorry if my actual question seems to differ a bit. I actually get the pointer to the lua function stored in a list which is read from C. The point here is that from C I don't really know which function is to be passed, I just want a reference of it to be stored so I can call it from C. How would you do that? (Sorry for the change)
@Alec: I've read you question & comment again, and again, and it seems that it's exactly the question I've answered. I've edited my answer to include a solution using the "registry", but the concept is the same. I've added nothing really new. Let me repeat: You can't directly store in C a reference to a Lua function. The reference is kept on the Lua side. What you have on your C side is some key that allows you to retrieve ("push") the Lua function onto the stack.
It really makes a difference, in my specific scenario I have no idea what is in the Lua side, the code is completely not controlled by me (they are mods for a game), where I let the mod developer specify functions to be called. That is why your second method works for me.
I know this is an old post, but where does L come from in lua_rawgeti(L, LUA_REGISTRYINDEX, the_mouse_click_handler);? Is the lua_State* stored globally within the C code? If the C code wants to trigger an asynchronous callback, how does it access lua_State?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.