Skip to content

Lua C API Guide — Embedding and Extending Lua in C Programs

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Lua C API Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

The Lua C API is the interface between C and Lua -- using a virtual stack to pass data between the two languages, enabling bidirectional communication for embedding Lua in applications or extending Lua with C libraries.

What You'll Learn

  • The Lua stack model and how data flows between C and Lua
  • Embedding Lua in a C program
  • Exposing C functions to Lua
  • Handling errors between the two languages

Why It Matters

The C API is what makes Lua embeddable. Games, security tools, and embedded systems use it to provide scripting in their applications. Durga Antivirus Pro embeds Lua through the C API to run user-defined threat detection rules in a sandboxed environment.

The Lua Stack

The C API communicates with Lua through a virtual stack. Values are pushed onto the stack by C, read by Lua, and vice versa.

#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

int main() {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    // Push values onto the stack
    lua_pushnumber(L, 42);
    lua_pushstring(L, "hello");
    lua_pushboolean(L, 1);

    // Read from stack
    double num = lua_tonumber(L, -3);
    const char *str = lua_tostring(L, -2);
    int bool_val = lua_toboolean(L, -1);

    printf("Stack values: %f, %s, %d\n", num, str, bool_val);

    lua_close(L);
    return 0;
}

Running Lua Scripts from C

#include <lua.h>
#include <lauxlib.h>

int main() {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    // Run a Lua expression
    if (luaL_dostring(L, "print('Hello from Lua!')") != LUA_OK) {
        const char *err = lua_tostring(L, -1);
        printf("Error: %s\n", err);
        lua_pop(L, 1);
    }

    // Run a Lua file
    if (luaL_dofile(L, "script.lua") != LUA_OK) {
        const char *err = lua_tostring(L, -1);
        printf("Error: %s\n", err);
        lua_pop(L, 1);
    }

    lua_close(L);
    return 0;
}

Calling Lua Functions from C

// Assume Lua has: function add(a, b) return a + b end
lua_getglobal(L, "add");       // push function
lua_pushnumber(L, 10);         // push argument 1
lua_pushnumber(L, 20);         // push argument 2

if (lua_pcall(L, 2, 1, 0) != LUA_OK) {
    const char *err = lua_tostring(L, -1);
    printf("Error: %s\n", err);
} else {
    double result = lua_tonumber(L, -1);
    printf("Result: %f\n", result);  // 30
    lua_pop(L, 1);                   // pop result
}

Exposing C Functions to Lua

// C function to expose
static int c_add(lua_State *L) {
    double a = luaL_checknumber(L, 1);
    double b = luaL_checknumber(L, 2);
    lua_pushnumber(L, a + b);
    return 1;  // number of return values
}

// Register with Lua
lua_register(L, "add", c_add);

// Now Lua can call: add(10, 20) -> 30

Error Handling

// Using protected calls
if (lua_pcall(L, nargs, nresults, msgh) != LUA_OK) {
    const char *msg = lua_tostring(L, -1);
    fprintf(stderr, "Lua error: %s\n", msg);
    lua_pop(L, 1);  // remove error message
    return 0;
}

Common Mistakes

1. Stack leaks

Every push must be matched by a pop. Not balancing the stack causes memory growth.

2. Forgetting to check types

Always use luaL_check* functions to validate argument types. Without them, invalid input causes undefined behavior.

3. Using negative indices incorrectly

Negative indices count from the top (-1 = top). Positive indices count from the bottom (1 = bottom). Know which you're using.

4. Not checking pcall return

lua_pcall can fail. Always check the return value and handle errors.

5. Memory management

Lua's garbage collector doesn't know about C allocations. Use proper cleanup or risk memory leaks.

Practice Questions

1. What is the Lua stack? A virtual stack used for all communication between C and Lua. Values are pushed by one side and read by the other.

2. How do you call a Lua function from C? Push the function onto the stack, push arguments, call lua_pcall, then read results from the stack.

3. What does lua_pcall return on success vs error? Returns LUA_OK on success. Returns LUA_ERRRUN, LUA_ERRMEM, or LUA_ERRERR on errors.

FAQ

{{< faq question="Do I need to know C to use Lua?" >}} No. The C API is only needed when embedding Lua in C applications or writing C extension modules. Most Lua users never touch the C API. {{< /faq >}}

{{< faq question="Can I use the C API from C++?" >}} Yes. The Lua headers work with C++. Compile with a C++ compiler, or wrap C headers in extern "C" {}. {{< /faq >}}

{{< faq question="What is lua_State?" >}} The main state object representing a Lua Interpreter instance. Each Lua VM has one lua_State. Multiple states are independent. {{< /faq >}}

{{< faq question="Can multiple C threads share one Lua state?" >}} No. Lua states are not thread-safe. Use one state per thread, or use Lua's built-in coroutines for concurrency within one state. {{< /faq >}}

{{< faq question="What is LuaJIT's FFI?" >}} LuaJIT's FFI (Foreign Function Interface) lets you call C functions directly from Lua without writing C wrapper code. It's much simpler than the standard C API for many use cases. {{< /faq >}}

What's Next

Now that you understand the C API, apply your Lua skills to Game Development with Love2D.

Topic Description Link
Love2D Game development framework {{< ref "12-love2d" >}}
LuaRocks Package manager {{< ref "13-luarocks" >}}
C Compare with standard C Programming C

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro