Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

  1. Home
  2. Lua Dictionary
  3. C API (Lua-C Integration)

C API (Lua-C Integration)

Lua is designed as a scripting engine that can be embedded in C/C++ applications. Through the C API, a host program can manipulate the Lua stack to execute Lua scripts, pass values, and expose C functions to Lua.

Syntax

/* -----------------------------------------------
 * Basic usage of the Lua C API
 * ----------------------------------------------- */
#include <lua.h>       /* defines the Lua core API */
#include <lualib.h>    /* defines functions for opening standard libraries */
#include <lauxlib.h>   /* defines the auxiliary library (luaL_*) */

/* Create and destroy a Lua state */
lua_State *L = luaL_newstate();   /* creates a new Lua state */
luaL_openlibs(L);                 /* loads standard libraries (io, math, etc.) */
lua_close(L);                     /* destroys the state and frees memory */

/* Execute a Lua script */
luaL_dostring(L, "print('hello')");   /* compiles and runs a string directly */
luaL_dofile(L, "script.lua");         /* loads a file and executes it */

/* Pushing values onto the stack */
lua_pushstring(L, "world");    /* pushes a string onto the stack */
lua_pushnumber(L, 42.0);       /* pushes a number onto the stack */
lua_pushboolean(L, 1);         /* pushes a boolean onto the stack */
lua_pushnil(L);                /* pushes nil onto the stack */

/* Reading values from the stack */
const char *s = lua_tostring(L, -1);   /* gets the string at the stack top */
double n      = lua_tonumber(L, -1);   /* gets the number at the stack top */
int b         = lua_toboolean(L, -1);  /* gets the boolean at the stack top */

/* Exposing a C function to Lua */
static int my_func(lua_State *L) {
    /* arguments are retrieved by stack index starting at 1 */
    const char *name = lua_tostring(L, 1);
    lua_pushstring(L, name);  /* push the return value onto the stack */
    return 1;                 /* return the number of return values */
}
lua_pushcfunction(L, my_func);   /* push the C function onto the stack */
lua_setglobal(L, "my_func");     /* register it as a global variable */

API Reference

FunctionDescription
luaL_newstate()Creates and returns a new Lua state (execution environment).
luaL_openlibs(L)Loads all standard libraries (io / math / string / table, etc.).
lua_close(L)Destroys the Lua state and releases all resources.
luaL_dostring(L, s)Compiles and executes the C string s as a Lua script.
luaL_dofile(L, path)Loads a file from disk and compiles and executes it.
lua_getglobal(L, name)Pushes the value of a global variable onto the stack.
lua_setglobal(L, name)Sets the stack top value as a global variable and pops it from the stack.
lua_pushstring(L, s)Pushes a C string onto the stack.
lua_pushnumber(L, n)Pushes a number onto the stack.
lua_pushboolean(L, b)Pushes a boolean onto the stack.
lua_pushnil(L)Pushes nil onto the stack.
lua_pushcfunction(L, f)Pushes a C function onto the stack.
lua_tostring(L, idx)Returns the value at index idx as a C string.
lua_tonumber(L, idx)Returns the value at index idx as a lua_Number (double).
lua_toboolean(L, idx)Returns the value at index idx as a C integer (0 or non-zero).
lua_type(L, idx)Returns the type of the value at index idx as an integer constant (e.g., LUA_TSTRING).
lua_pcall(L, nargs, nrets, msgh)Calls a Lua function in protected mode. On error, pushes a message onto the stack and returns a non-zero value.
lua_pop(L, n)Removes n values from the top of the stack and discards them.
lua_gettop(L)Returns the current stack size (the number of values on the stack).

Sample Code

embed_lua.c
/* embed_lua.c — uses KOF (THE KING OF FIGHTERS) fighter data
 * as a C and Lua interoperability sample.
 * Fighter data is defined on the C side and accessed from a Lua script
 * to aggregate and display it.
 *
 * Compile: gcc embed_lua.c -o embed_lua -llua && ./embed_lua
 */

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

/* -----------------------------------------------
 * C function: adds two power values and returns the result
 * Called from Lua as  add_power(a, b)
 * ----------------------------------------------- */
static int add_power(lua_State *L) {
    double a = lua_tonumber(L, 1);  /* get the first argument */
    double b = lua_tonumber(L, 2);  /* get the second argument */
    lua_pushnumber(L, a + b);       /* push the sum onto the stack */
    return 1;                       /* one return value */
}

/* -----------------------------------------------
 * C function: converts a character name to uppercase and returns it
 * Called from Lua as  to_upper(s)
 * ----------------------------------------------- */
static int to_upper(lua_State *L) {
    const char *src = luaL_checkstring(L, 1);  /* verify and get the string argument */
    char buf[128];
    int i;
    for (i = 0; src[i] && i < 127; i++) {
        buf[i] = (src[i] >= 'a' && src[i] <= 'z') ? src[i] - 32 : src[i];
    }
    buf[i] = '\0';
    lua_pushstring(L, buf);  /* push the converted string onto the stack */
    return 1;
}

/* the Lua script body (embedded as a C string) */
static const char *LUA_SCRIPT =
    "-- define the KOF fighter power table\n"
    "local fighters = {\n"
    "  { name = 'Kyo Kusanagi',   power = 9800 },\n"
    "  { name = 'Iori Yagami',    power = 9900 },\n"
    "  { name = 'Terry Bogard',   power = 9600 },\n"
    "  { name = 'Athena Asamiya', power = 9400 },\n"
    "  { name = 'Leona Heidern',  power = 9700 },\n"
    "}\n"
    "\n"
    "print('=== KOF Fighter Power Report ===')\n"
    "print('')\n"
    "\n"
    "-- display each fighter's information\n"
    "local total = 0\n"
    "for _, f in ipairs(fighters) do\n"
    "  -- call to_upper() registered on the C side\n"
    "  local upper_name = to_upper(f.name)\n"
    "  print(string.format('  %-22s  Power: %d', upper_name, f.power))\n"
    "  total = add_power(total, f.power)  -- add with add_power() from C\n"
    "end\n"
    "\n"
    "print('')\n"
    "print(string.format('Total power: %d', total))\n"
    "print(string.format('Average power: %.1f', total / #fighters))\n"
    "print('')\n"
    "print('Functions registered via C API are working correctly.')\n";

int main(void) {
    /* -----------------------------------------------
     * Create the Lua state
     * ----------------------------------------------- */
    lua_State *L = luaL_newstate();
    if (!L) {
        fprintf(stderr, "Failed to create Lua state\n");
        return EXIT_FAILURE;
    }

    /* load standard libraries (io, string, math, table, etc.) */
    luaL_openlibs(L);

    /* -----------------------------------------------
     * Register C functions as Lua global variables
     * ----------------------------------------------- */
    lua_pushcfunction(L, add_power);   /* push the function pointer onto the stack */
    lua_setglobal(L, "add_power");     /* set as global variable add_power */

    lua_pushcfunction(L, to_upper);
    lua_setglobal(L, "to_upper");

    /* -----------------------------------------------
     * Execute the Lua script
     * ----------------------------------------------- */
    int ret = luaL_dostring(L, LUA_SCRIPT);
    if (ret != LUA_OK) {
        /* on error, an error message is pushed onto the stack top */
        fprintf(stderr, "Lua error: %s\n", lua_tostring(L, -1));
        lua_pop(L, 1);  /* remove the error message from the stack */
        lua_close(L);
        return EXIT_FAILURE;
    }

    /* -----------------------------------------------
     * Read a Lua global variable from C
     * ----------------------------------------------- */
    lua_getglobal(L, "total");           /* push the global variable total onto the stack */
    if (lua_type(L, -1) == LUA_TNUMBER) {
        printf("[C side] Lua total variable: %.0f\n", lua_tonumber(L, -1));
    }
    lua_pop(L, 1);  /* discard the retrieved value from the stack */

    /* -----------------------------------------------
     * Close the Lua state and release resources
     * ----------------------------------------------- */
    lua_close(L);
    return EXIT_SUCCESS;
}
gcc embed_lua.c -o embed_lua -llua && ./embed_lua
=== KOF Fighter Power Report ===

  KYO KUSANAGI           Power: 9800
  IORI YAGAMI            Power: 9900
  TERRY BOGARD           Power: 9600
  ATHENA ASAMIYA         Power: 9400
  LEONA HEIDERN          Power: 9700

Total power: 48400
Average power: 9680.0

Functions registered via C API are working correctly.
[C side] Lua total variable: 48400

Common Mistakes

Common Mistake 1: Returning the wrong number of return values from a C function

A C function exposed to Lua must return the exact count of values it pushed onto the stack. If the number returned by the return statement does not match the number of values actually pushed, the values received on the Lua side will be incorrect.

ng_example.c
/* pushes 2 values onto the stack but incorrectly returns 1 */
static int bad_func(lua_State *L) {
    lua_pushstring(L, "Kyo Kusanagi");
    lua_pushnumber(L, 9800);
    return 1;  /* should be return 2 since 2 values were pushed */
}

Match the return value to the number of values pushed onto the stack.

ok_example.c
static int good_func(lua_State *L) {
    lua_pushstring(L, "Kyo Kusanagi");
    lua_pushnumber(L, 9800);
    return 2;  /* 2 values were pushed, so return 2 */
}

Common Mistake 2: Using the lua_tostring() pointer after calling lua_pop()

The pointer returned by lua_tostring() points directly into the string on the stack. Once that value is removed from the stack with lua_pop() or any similar operation, the memory the pointer refers to may become invalid. Either avoid popping the value before you are done with the pointer, or copy the string into a buffer first using strcpy() or similar.

ng_example2.c
lua_getglobal(L, "fighter_name");
const char *name = lua_tostring(L, -1);
lua_pop(L, 1);          /* the value is removed from the stack */
printf("%s\n", name);   /* name may now point to invalid memory */

Copy the string into a buffer before removing it from the stack.

ok_example2.c
lua_getglobal(L, "fighter_name");
const char *name = lua_tostring(L, -1);
char buf[128];
strncpy(buf, name, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
lua_pop(L, 1);      /* pop after copying */
printf("%s\n", buf);

Overview

The Lua C API is entirely stack-based. Values are pushed onto the stack when passing them from C to Lua, and return values from Lua to C are also placed on the stack. Indices can be positive (counting from the stack bottom) or negative (counting from the stack top, with -1 being the top). To expose a C function to Lua, register it using lua_pushcfunction followed by lua_setglobal. luaL_dostring and luaL_dofile are convenient for running scripts, but when fine-grained error handling is needed, use luaL_loadstring combined with lua_pcall to execute in protected mode. Compiling against the Lua library requires the -llua flag, and the three headers <lua.h>, <lualib.h>, and <lauxlib.h> must be included. For creating Lua-side modules, also see LuaRocks (Package Manager).

If you find any errors or copyright issues, please .