Embebiendo Lua en C — Tutorial para Principiantes
En este artículo aprenderás cómo embeber (integrar) el lenguaje Lua dentro de un programa C. Esto es más sencillo de lo que parece, y abre muchas posibilidades interesantes.
¿Qué es “embeber Lua en C”?
Imagina que tienes un programa en C y quieres permitir que los usuarios escriban scripts para personalizar su comportamiento — sin necesidad de recompilar el programa. Lua es perfecta para esto.
Al embeber Lua, tu programa C puede: - Ejecutar código Lua en tiempo real - Leer resultados calculados por Lua - Exponer funciones C para que el código Lua las use
Requisitos previos
Antes de comenzar, necesitas saber: - Lo básico de C (variables,
funciones, printf) - Tener gcc instalado en tu
sistema
No es necesario saber Lua. Los ejemplos son lo suficientemente simples como para entenderlos por contexto.
¿Para qué sirve esto en la práctica?
Evaluación Segura (Safe Evaluation)
Es posible ejecutar código Lua proporcionado por el usuario sin preocuparse por inyecciones de código malicioso. Esto es extremadamente útil para crear plugins, extensiones y plataformas no-code (como es el caso de OUI).
Creación de Plataformas No-Code
Puedes crear un sistema donde tus usuarios escriban scripts en Lua para automatizar tareas o crear plugins — sin necesidad de tocar el código C de tu programa.
Creación de Runtimes
Al igual que se hizo en VibeScript y en Darwin, puedes crear runtimes con bibliotecas embebidas para los casos de uso más diversos.
Instalación
En este tutorial usamos LuaCEmbed, una biblioteca que simplifica bastante el trabajo con Lua en C.
Paso 1: Descarga la biblioteca con un solo comando:
curl -L https://github.com/OUIsolutions/LuaCEmbed/releases/download/0.13.0/LuaCEmbedOne.c -o LuaCEmbedOne.cPaso 2: Crea un archivo main.c e
incluye la biblioteca en la parte superior:
#include "LuaCEmbedOne.c" // incluye toda la biblioteca
int main() {
// tu código aquí
}La biblioteca es single-file (archivo único), por lo que no es necesario instalar nada — basta con incluirla.
Compilación
En Linux:
gcc main.c -o programa.outEn Windows con MinGW:
i686-w64-mingw32-gcc main.c -o programa.exe -lws2_32En Windows con MSVC:
cl.exe main.c /Fe:programa.exeEjemplo Básico
Vamos a empezar con el ejemplo más simple posible: ejecutar un cálculo en Lua y leer el resultado de vuelta en C.
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
// 1. Crea una nueva "máquina virtual" Lua
LuaCEmbed *l = newLuaCEmbedEvaluation();
// 2. Ejecuta código Lua: define la variable 'r' como 30
LuaCEmbed_evaluate(l, "r = 30");
// 3. Evalúa una expresión Lua y lee el resultado como un número entero (long)
long calc = LuaCEmbed_get_evaluation_long(l, "r + 20");
printf("resultado: %ld\n", calc); // imprime: 50
// 4. Verifica si ocurrió algún error durante la ejecución
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
// 5. Libera la memoria usada por la máquina virtual
LuaCEmbed_free(l);
return 0;
}Salida:
resultado: 50
Patrón que repetirás en todos los ejemplos: 1.
newLuaCEmbedEvaluation()— crea la instancia 2.LuaCEmbed_evaluate()— ejecuta código Lua 3. Lee el resultado con las funcionesget_evaluation_*4. Verifica errores conLuaCEmbed_has_errors5.LuaCEmbed_free()— libera la memoria
Leyendo Valores de Lua
String
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_evaluate(l, "r = 'hello world'");
// Lee la variable 'r' como texto
char *result = LuaCEmbed_get_evaluation_string(l, "r");
printf("resultado: %s\n", result);
LuaCEmbed_free(l);
return 0;
}Salida:
resultado: hello world
Número entero (long)
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_evaluate(l, "r = 20 + 30");
long result = LuaCEmbed_get_evaluation_long(l, "r");
printf("resultado: %ld\n", result);
LuaCEmbed_free(l);
return 0;
}Salida:
resultado: 50
Número decimal (double)
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_evaluate(l, "r = 20 + 30");
double result = LuaCEmbed_get_evaluation_double(l, "r");
printf("resultado: %lf\n", result);
LuaCEmbed_free(l);
return 0;
}Salida:
resultado: 50.000000
Booleano
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_evaluate(l, "r = true");
bool result = LuaCEmbed_get_evaluation_bool(l, "r");
printf("resultado: %d\n", result); // 1 = true, 0 = false
LuaCEmbed_free(l);
return 0;
}Salida:
resultado: 1
Descubriendo el tipo de una variable
Si no sabes qué tipo tiene la variable, puedes comprobarlo antes de leer:
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_evaluate(l, "r = 'hello world'");
int r_type = LuaCEmbed_get_evaluation_type(l, "r");
const char *type_name = LuaCembed_convert_arg_code(r_type);
printf("tipo: %s\n", type_name);
LuaCEmbed_free(l);
return 0;
}Salida:
tipo: string
Funciones Nativas de Lua
Por defecto, LuaCEmbed no expone las funciones
nativas de Lua (como print, io,
os, etc.) al código evaluado. Esto es intencional —
garantiza que código de terceros no pueda acceder a archivos o ejecutar
comandos en tu sistema.
Si confías en el código que vas a ejecutar y necesitas estas funciones:
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
// ATENCIÓN: ¡solo usa esto si confías en el código que será ejecutado!
// Esto da acceso a print, io, os, y otras librerías nativas de Lua.
LuaCEmbed_load_native_libs(l);
LuaCEmbed_evaluate(l, "print('hello from lua')");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Salida:
hello from lua
Ejecutando un archivo .lua
En lugar de pasar código como string, puedes cargar un archivo
.lua del disco:
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_load_native_libs(l);
// Carga y ejecuta el archivo "script.lua"
LuaCEmbed_evaluete_file(l, "script.lua");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Callbacks — Exponiendo Funciones C a Lua
Los callbacks son la manera de crear funciones en C que pueden ser llamadas desde el código Lua. Esto te permite definir exactamente qué puede o no puede hacer el usuario.
Callback simple (sin argumentos, sin retorno)
#include "LuaCEmbedOne.c"
// Esta función C será llamable desde Lua
LuaCEmbedResponse *hello(LuaCEmbed *args) {
printf("mi primer callback\n");
return NULL; // NULL significa: no devuelve nada (nil en Lua)
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
// Registra la función C con el nombre "hello" en Lua
LuaCEmbed_add_callback(l, "hello", hello);
// Ahora el código Lua puede llamar a hello()
LuaCEmbed_evaluate(l, "hello()");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Salida:
mi primer callback
Recibiendo argumentos en el callback
Los argumentos pasados por Lua están disponibles dentro de la función C. Se indexan a partir de 0 (estándar de C), aunque Lua normalmente use índices a partir de 1.
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *test_func(LuaCEmbed *args) {
// ¿Cuántos argumentos se proporcionaron?
long size = LuaCEmbed_get_total_args(args);
if (size == 0) {
printf("ningún argumento proporcionado\n");
return NULL;
}
// Lee el primer argumento (índice 0)
int index = 0;
int arg_type = LuaCEmbed_get_arg_type(args, index);
// Actúa según el tipo recibido
if (arg_type == LUA_CEMBED_NUMBER) {
printf("número: %lf\n", LuaCEmbed_get_double_arg(args, index));
} else if (arg_type == LUA_CEMBED_STRING) {
printf("string: %s\n", LuaCEmbed_get_str_arg(args, index));
} else if (arg_type == LUA_CEMBED_BOOL) {
printf("bool: %d\n", LuaCEmbed_get_bool_arg(args, index));
} else {
// Para otros tipos (como tabla), muestra el nombre del tipo
const char *type_name = LuaCembed_convert_arg_code(arg_type);
printf("tipo: %s\n", type_name);
}
return NULL;
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_add_callback(l, "test", test_func);
// Prueba con diferentes tipos de argumento
LuaCEmbed_evaluate(l, "test()"); // sin argumento
LuaCEmbed_evaluate(l, "test(10)"); // número
LuaCEmbed_evaluate(l, "test('hello')"); // string
LuaCEmbed_evaluate(l, "test(true)"); // booleano
LuaCEmbed_evaluate(l, "test({a=30})"); // tabla
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Salida:
ningún argumento proporcionado
número: 10.000000
string: hello
bool: 1
tipo: table
Retornando valores desde un callback
Un callback puede devolver un valor a Lua usando las funciones
LuaCEmbed_send_*:
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *add(LuaCEmbed *args) {
double a = LuaCEmbed_get_double_arg(args, 0);
double b = LuaCEmbed_get_double_arg(args, 1);
// Si hubo un error al leer los argumentos (ej: tipo incorrecto), propaga el error
if (LuaCEmbed_has_errors(args)) {
return LuaCEmbed_send_error(LuaCEmbed_get_error_message(args));
}
return LuaCEmbed_send_double(a + b); // devuelve la suma a Lua
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_add_callback(l, "add", add);
double result = LuaCEmbed_get_evaluation_double(l, "add(10, 20)");
printf("resultado: %lf\n", result);
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Salida:
resultado: 30.000000
Funciones de retorno disponibles:
| Función | Retorna |
|---|---|
LuaCEmbed_send_double(double) |
número decimal |
LuaCEmbed_send_long(long) |
número entero |
LuaCEmbed_send_str(char*) |
texto |
LuaCEmbed_send_bool(bool) |
verdadero/falso |
LuaCEmbed_send_table(LuaCEmbedTable*) |
tabla |
LuaCEmbed_send_error(char*) |
propaga un error a Lua |
return NULL |
nil (sin retorno) |
Tablas
Las tablas son el principal tipo de estructura de datos de Lua — funcionan como arrays, diccionarios y objetos al mismo tiempo.
Leyendo propiedades de una tabla recibida
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *show_table(LuaCEmbed *args) {
// Lee el primer argumento como tabla
LuaCEmbedTable *t = LuaCEmbed_get_arg_table(args, 0);
if (LuaCEmbed_has_errors(args)) {
return LuaCEmbed_send_error(LuaCEmbed_get_error_message(args));
}
// Lee las propiedades por el nombre
char *name = LuaCembedTable_get_string_prop(t, "name");
long age = LuaCembedTable_get_long_prop(t, "age");
printf("nombre: %s\n", name);
printf("edad: %ld\n", age);
return NULL;
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_add_callback(l, "show_table", show_table);
LuaCEmbed_evaluate(l, "show_table({ name = 'Mateus', age = 27 })");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Salida:
nombre: Mateus
edad: 27
Tamaño de una tabla
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_evaluate(l, "r = {1, 2, 3}");
long size = LuaCEmbed_get_evaluation_table_size(l, "r");
printf("tamaño: %ld\n", size); // 3
LuaCEmbed_free(l);
return 0;
}Salida:
tamaño: 3
Iterando sobre los elementos de una tabla
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *show_table(LuaCEmbed *args) {
LuaCEmbedTable *t = LuaCEmbed_get_arg_table(args, 0);
if (LuaCEmbed_has_errors(args)) {
return LuaCEmbed_send_error(LuaCEmbed_get_error_message(args));
}
long size = LuaCEmbedTable_get_listable_size(t);
for (int i = 0; i < size; i++) {
printf("índice: %d\n", i);
// Verifica si el elemento tiene una clave (string) asociada
const char *key = "sin clave";
if (LuaCembedTable_has_key_at_index(t, i)) {
key = LuaCembedTable_get_key_by_index(t, i);
}
printf("clave: %s\n", key);
// Lee el tipo y el valor del elemento
int type = LuaCEmbedTable_get_type_by_index(t, i);
printf("tipo: %s\n", LuaCembed_convert_arg_code(type));
if (type == LUA_CEMBED_NUMBER) {
printf("valor: %lf\n", LuaCEmbedTable_get_double_by_index(t, i));
} else if (type == LUA_CEMBED_STRING) {
printf("valor: %s\n", LuaCEmbedTable_get_string_by_index(t, i));
} else if (type == LUA_CEMBED_BOOL) {
printf("valor: %d\n", LuaCEmbedTable_get_bool_by_index(t, i));
}
printf("--\n");
}
return NULL;
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_add_callback(l, "show_table", show_table);
LuaCEmbed_evaluate(l, "show_table({10, 'hello', true, x=42})");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Leyendo sub-tablas (tablas dentro de tablas)
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *show_people(LuaCEmbed *args) {
LuaCEmbedTable *t = LuaCEmbed_get_arg_table(args, 0);
if (LuaCEmbed_has_errors(args)) {
return LuaCEmbed_send_error(LuaCEmbed_get_error_message(args));
}
long size = LuaCEmbedTable_get_listable_size(t);
for (int i = 0; i < size; i++) {
// Cada elemento es una tabla con "name" y "age"
LuaCEmbedTable *item = LuaCEmbedTable_get_sub_table_by_index(t, i);
char *name = LuaCembedTable_get_string_prop(item, "name");
long age = LuaCembedTable_get_long_prop(item, "age");
printf("nombre: %s, edad: %ld\n", name, age);
}
return NULL;
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_add_callback(l, "show_people", show_people);
LuaCEmbed_evaluate(l, "show_people({{name='Alice', age=30}, {name='Bob', age=25}})");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Salida:
nombre: Alice, edad: 30
nombre: Bob, edad: 25
Creando y retornando una tabla de C a Lua
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *create_table(LuaCEmbed *args) {
// Crea una nueva tabla vacía
LuaCEmbedTable *t = LuaCembed_new_anonymous_table(args);
// Define las propiedades
LuaCEmbedTable_set_string_prop(t, "name", "Mateus");
LuaCEmbedTable_set_long_prop (t, "age", 27);
LuaCEmbedTable_set_double_prop(t, "height", 1.82);
LuaCEmbedTable_set_bool_prop (t, "married", false);
// Devuelve la tabla a Lua
return LuaCEmbed_send_table(t);
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_add_callback(l, "create_table", create_table);
LuaCEmbed_load_native_libs(l);
LuaCEmbed_evaluate(l, "p = create_table(); print(p.name, p.age, p.height, p.married)");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Salida:
Mateus 27 1.82 false
Añadiendo métodos a una tabla
Puedes crear tablas que se comportan como objetos, con métodos invocables por Lua:
#include "LuaCEmbedOne.c"
// El método recibe la propia tabla como 'self' (como en orientación a objetos)
LuaCEmbedResponse *describe(LuaCEmbedTable *self, LuaCEmbed *args) {
char *name = LuaCembedTable_get_string_prop(self, "name");
long age = LuaCembedTable_get_long_prop(self, "age");
printf("nombre: %s, edad: %ld\n", name, age);
return NULL;
}
LuaCEmbedResponse *create_table(LuaCEmbed *args) {
LuaCEmbedTable *t = LuaCembed_new_anonymous_table(args);
LuaCEmbedTable_set_string_prop(t, "name", "Mateus");
LuaCEmbedTable_set_long_prop (t, "age", 27);
LuaCEmbedTable_set_method (t, "describe", describe);
return LuaCEmbed_send_table(t);
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_add_callback(l, "create_table", create_table);
LuaCEmbed_evaluate(l, "local p = create_table(); p:describe()");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Salida:
nombre: Mateus, edad: 27
Meta-métodos
Los meta-métodos te permiten interceptar operaciones especiales de
Lua, como el acceso a propiedades (__index) y la
destrucción por el recolector de basura (__gc):
#include "LuaCEmbedOne.c"
// Invocado cuando Lua accede a una propiedad de la tabla
LuaCEmbedResponse *index_callback(LuaCEmbedTable *self, LuaCEmbed *args) {
int value_type = LuaCEmbed_get_arg_type(args, 1);
if (value_type == LUA_CEMBED_STRING) {
printf("acceso al índice: %s\n", LuaCEmbed_get_str_arg(args, 1));
}
return NULL;
}
// Invocado cuando el recolector de basura de Lua destruye la tabla
LuaCEmbedResponse *gc_callback(LuaCEmbedTable *self, LuaCEmbed *args) {
printf("tabla destruida por el GC\n");
return NULL;
}
LuaCEmbedResponse *create_table(LuaCEmbed *args) {
LuaCEmbedTable *t = LuaCembed_new_anonymous_table(args);
LuaCEmbedTable_set_method(t, "__index", index_callback);
LuaCEmbedTable_set_method(t, "__gc", gc_callback);
return LuaCEmbed_send_table(t);
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_add_callback(l, "create_table", create_table);
LuaCEmbed_evaluate(l, "local t = create_table(); local x = t.foo");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Salida:
acceso al índice: foo
tabla destruida por el GC
Creando una Biblioteca (.so/.dll)
Además de ejecutar Lua desde C, también puedes hacer el camino
inverso: compilar C como una biblioteca dinámica e importarla
directamente desde Lua con require.
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *add_cfunc(LuaCEmbed *args) {
double a = LuaCEmbed_get_double_arg(args, 0);
double b = LuaCEmbed_get_double_arg(args, 1);
if (LuaCEmbed_has_errors(args)) {
return LuaCEmbed_send_error(LuaCEmbed_get_error_message(args));
}
return LuaCEmbed_send_double(a + b);
}
LuaCEmbedResponse *sub_cfunc(LuaCEmbed *args) {
double a = LuaCEmbed_get_double_arg(args, 0);
double b = LuaCEmbed_get_double_arg(args, 1);
if (LuaCEmbed_has_errors(args)) {
return LuaCEmbed_send_error(LuaCEmbed_get_error_message(args));
}
return LuaCEmbed_send_double(a - b);
}
// El nombre de la función DEBE ser "luaopen_" + nombre_de_la_biblioteca
int luaopen_my_lib(lua_State *state) {
LuaCEmbed *l = newLuaCEmbedLib(state);
LuaCEmbed_add_callback(l, "add", add_cfunc);
LuaCEmbed_add_callback(l, "sub", sub_cfunc);
return LuaCembed_perform(l);
}Compila como biblioteca compartida:
gcc -shared -fPIC -o my_lib.so main.cUsa en Lua:
local lib = require("my_lib")
print(lib.add(10, 20)) -- 30.0
print(lib.sub(20, 5)) -- 15.0Propiedades estáticas en la biblioteca
También puedes exponer constantes y valores fijos:
int luaopen_my_lib(lua_State *state) {
LuaCEmbed *l = newLuaCEmbedLib(state);
LuaCEmbed_set_long_lib_prop (l, "version", 1);
LuaCEmbed_set_string_lib_prop(l, "author", "Mateus");
LuaCEmbed_set_double_lib_prop(l, "pi", 3.14);
LuaCEmbed_set_bool_lib_prop (l, "debug", false);
return LuaCembed_perform(l);
}En Lua:
local lib = require("my_lib")
print(lib.version) -- 1
print(lib.author) -- MateusSeguridad: Timeout y Límite de Memoria
Cuando ejecutas código enviado por usuarios, es importante proteger tu programa contra bucles infinitos y uso excesivo de memoria.
Timeout
Interrumpe la ejecución después de un número de segundos:
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_set_timeout(2); // interrumpe tras 2 segundos
LuaCEmbed_evaluate(l, "while true do end"); // bucle infinito
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
// Tras un timeout, puedes limpiar el error y seguir usando la instancia
LuaCEmbed_clear_errors(l);
LuaCEmbed_evaluate(l, "r = 'todavía funciona'");
printf("%s\n", LuaCEmbed_get_evaluation_string(l, "r"));
LuaCEmbed_free(l);
return 0;
}Salida:
error: timeout error
todavía funciona
Límite de Memoria
Impide que el código Lua consuma memoria de manera incontrolada (por defecto: 100 MB):
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_set_memory_limit(l, 1); // limita a 1 MB
// Código que intenta aumentar una cadena indefinidamente
LuaCEmbed_evaluate(l, "t = 'a'; while true do t = t .. t end");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Salida:
error: not enough memory
Tratamiento de Errores
Siempre comprueba si hay errores después de cada evaluación. Si no lo haces, errores silenciosos podrían causar un comportamiento inesperado.
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *mi_funcion(LuaCEmbed *args) {
double val = LuaCEmbed_get_double_arg(args, 0);
if (LuaCEmbed_has_errors(args)) {
// Propaga el error a Lua en vez de continuar con un valor inválido
return LuaCEmbed_send_error(LuaCEmbed_get_error_message(args));
}
return LuaCEmbed_send_double(val * 2);
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_evaluate(l, "código inválido %%%");
if (LuaCEmbed_has_errors(l)) {
printf("error: %s\n", LuaCEmbed_get_error_message(l));
// Limpia el error para continuar usando la misma instancia
LuaCEmbed_clear_errors(l);
}
LuaCEmbed_add_callback(l, "mi_funcion", mi_funcion);
double result = LuaCEmbed_get_evaluation_double(l, "mi_funcion(21)");
printf("resultado: %lf\n", result);
LuaCEmbed_free(l);
return 0;
}Salida:
error: [string "código inválido %%%"]:1: unexpected symbol near '%'
resultado: 42.000000
Referencia Rápida
| Función | Descripción |
|---|---|
newLuaCEmbedEvaluation() |
Crea una nueva instancia |
LuaCEmbed_evaluate(l, code) |
Ejecuta código Lua (string) |
LuaCEmbed_evaluete_file(l, path) |
Ejecuta un archivo Lua |
LuaCEmbed_load_native_libs(l) |
Habilita libs nativas (print, io, os…) |
LuaCEmbed_add_callback(l, name, fn) |
Registra una función C en Lua |
LuaCEmbed_get_evaluation_string(l, expr) |
Lee el resultado como string |
LuaCEmbed_get_evaluation_long(l, expr) |
Lee el resultado como entero |
LuaCEmbed_get_evaluation_double(l, expr) |
Lee el resultado como decimal |
LuaCEmbed_get_evaluation_bool(l, expr) |
Lee el resultado como booleano |
LuaCEmbed_get_evaluation_type(l, expr) |
Retorna el tipo de la expresión |
LuaCEmbed_get_evaluation_table_size(l, expr) |
Retorna el tamaño de una tabla |
LuaCEmbed_has_errors(l) |
Comprueba si hubo un error |
LuaCEmbed_get_error_message(l) |
Obtiene el mensaje de error |
LuaCEmbed_clear_errors(l) |
Limpia el estado de error |
LuaCEmbed_set_timeout(seconds) |
Define el timeout de ejecución |
LuaCEmbed_set_memory_limit(l, mb) |
Define el límite de memoria en MB |
LuaCEmbed_free(l) |
Libera la instancia |
