Lua C API
One of Lua's greatest strengths is its C API, which allows Lua to be embedded in applications and extended with C functions. This tutorial covers the basics of integrating Lua with C/C++.
Basic Embedding
Here's a simple C program that runs Lua code:
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
int main(void) {
// Create Lua state
lua_State *L = luaL_newstate();
// Load standard libraries
luaL_openlibs(L);
// Run Lua code
if (luaL_dostring(L, "print('Hello from Lua!')")) {
printf("Error: %s\n", lua_tostring(L, -1));
}
// Clean up
lua_close(L);
return 0;
}
Stack Basics
The Lua C API uses a stack to exchange values between C and Lua:
// Push values onto the stack
lua_pushnumber(L, 3.14);
lua_pushstring(L, "Hello");
// Get values from the stack
double num = lua_tonumber(L, -2); // 3.14
const char *str = lua_tostring(L, -1); // "Hello"
// Remove values from the stack
lua_pop(L, 2);
Calling Lua Functions from C
You can call Lua functions from C code:
// Assume Lua has a function called 'add' defined as:
// function add(a, b) return a + b end
// Get the function
lua_getglobal(L, "add");
// Push arguments
lua_pushnumber(L, 10);
lua_pushnumber(L, 20);
// Call the function (2 args, 1 return value)
if (lua_pcall(L, 2, 1, 0) != LUA_OK) {
printf("Error calling function: %s\n", lua_tostring(L, -1));
} else {
double result = lua_tonumber(L, -1);
printf("Result: %f\n", result); // 30
lua_pop(L, 1);
}
Registering C Functions in Lua
You can make C functions available to Lua:
// C function to be called from Lua
static int l_sin(lua_State *L) {
double d = luaL_checknumber(L, 1);
lua_pushnumber(L, sin(d));
return 1; // Number of return values
}
// Register the function
int main(void) {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_pushcfunction(L, l_sin);
lua_setglobal(L, "mysin");
luaL_dostring(L, "print(mysin(math.pi/2))"); // 1.0
lua_close(L);
return 0;
}
Userdata
Userdata allows you to expose C objects to Lua:
typedef struct {
double x, y;
} Point;
// Create a new Point
static int l_newpoint(lua_State *L) {
Point *p = (Point *)lua_newuserdata(L, sizeof(Point));
p->x = luaL_checknumber(L, 1);
p->y = luaL_checknumber(L, 2);
return 1;
}
// Get the x coordinate
static int l_point_getx(lua_State *L) {
Point *p = (Point *)lua_touserdata(L, 1);
lua_pushnumber(L, p->x);
return 1;
}
Metatables for Userdata
Metatables allow you to define behavior for userdata:
// Create metatable for Point
static const luaL_Reg point_methods[] = {
{"getx", l_point_getx},
{NULL, NULL}
};
int luaopen_point(lua_State *L) {
// Create metatable
luaL_newmetatable(L, "Point");
// Register methods
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
luaL_setfuncs(L, point_methods, 0);
// Register constructor
lua_pushcfunction(L, l_newpoint);
return 1;
}
Error Handling in C
Proper error handling is crucial in C API code:
static int l_divide(lua_State *L) {
double a = luaL_checknumber(L, 1);
double b = luaL_checknumber(L, 2);
if (b == 0.0) {
luaL_error(L, "division by zero");
}
lua_pushnumber(L, a / b);
return 1;
}
Next Steps
This concludes our Lua tutorial series. You can return to the tutorials page to explore other topics.