CodeToLive

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.