Embutindo Lua em C — Tutorial para Iniciantes
Neste artigo você vai aprender como embutir a linguagem Lua dentro de um programa C. Isso é mais simples do que parece, e abre muitas possibilidades interessantes.
O que é “embutir Lua em C”?
Imagine que você tem um programa em C e quer permitir que os usuários escrevam scripts para personalizar o comportamento dele — sem precisar recompilar o programa. Lua é perfeita para isso.
Ao embutir Lua, seu programa C consegue: - Executar código Lua em tempo real - Ler resultados calculados pelo Lua - Expor funções C para o código Lua usar
Pré-requisitos
Antes de começar, você precisa saber: - O básico de C (variáveis,
funções, printf) - Ter gcc instalado no seu
sistema
Não é necessário conhecer Lua. Os exemplos são simples o suficiente para entender pelo contexto.
Para que serve isso na prática?
Safe Evaluation (Avaliação Segura)
É possível executar código Lua fornecido pelo usuário sem se preocupar com injeções de código malicioso. Isso é extremamente útil para criar plugins, extensões e plataformas no-code (como é o caso da OUI).
Criação de Plataformas No-Code
Você pode criar um sistema onde seus usuários escrevem scripts em Lua para automatizar tarefas ou criar plugins — sem precisar mexer no código C do seu programa.
Criação de Runtimes
Assim como foi feito no VibeScript e no Darwin, você consegue criar runtimes com bibliotecas embutidas para os mais diversos casos de uso.
Instalação
Neste tutorial usamos o LuaCEmbed, uma biblioteca que simplifica bastante o trabalho com Lua em C.
Passo 1: Baixe a biblioteca com um único comando:
curl -L https://github.com/OUIsolutions/LuaCEmbed/releases/download/0.13.0/LuaCEmbedOne.c -o LuaCEmbedOne.cPasso 2: Crie um arquivo main.c e
inclua a biblioteca no topo:
#include "LuaCEmbedOne.c" // inclui toda a biblioteca
int main() {
// seu código aqui
}A biblioteca é single-file (arquivo único), então não precisa instalar nada — basta incluir.
Compilação
No Linux:
gcc main.c -o programa.outNo Windows com MinGW:
i686-w64-mingw32-gcc main.c -o programa.exe -lws2_32No Windows com MSVC:
cl.exe main.c /Fe:programa.exeExemplo Básico
Vamos começar com o exemplo mais simples possível: executar um cálculo em Lua e ler o resultado de volta em C.
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
// 1. Cria uma nova "máquina virtual" Lua
LuaCEmbed *l = newLuaCEmbedEvaluation();
// 2. Executa código Lua: define a variável 'r' como 30
LuaCEmbed_evaluate(l, "r = 30");
// 3. Avalia uma expressão Lua e lê o resultado como um número inteiro (long)
long calc = LuaCEmbed_get_evaluation_long(l, "r + 20");
printf("resultado: %ld\n", calc); // imprime: 50
// 4. Verifica se ocorreu algum erro durante a execução
if (LuaCEmbed_has_errors(l)) {
printf("erro: %s\n", LuaCEmbed_get_error_message(l));
}
// 5. Libera a memória usada pela máquina virtual
LuaCEmbed_free(l);
return 0;
}Saída:
resultado: 50
Padrão que você vai repetir em todos os exemplos: 1.
newLuaCEmbedEvaluation()— cria a instância 2.LuaCEmbed_evaluate()— executa código Lua 3. Lê o resultado com as funçõesget_evaluation_*4. Verifica erros comLuaCEmbed_has_errors5.LuaCEmbed_free()— libera a memória
Lendo Valores do Lua
String
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_evaluate(l, "r = 'hello world'");
// Lê a variável 'r' como texto
char *result = LuaCEmbed_get_evaluation_string(l, "r");
printf("resultado: %s\n", result);
LuaCEmbed_free(l);
return 0;
}Saída:
resultado: hello world
Número inteiro (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;
}Saída:
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;
}Saída:
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;
}Saída:
resultado: 1
Descobrindo o tipo de uma variável
Se você não sabe que tipo a variável tem, pode verificar antes de ler:
#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;
}Saída:
tipo: string
Funções Nativas do Lua
Por padrão, o LuaCEmbed não expõe as funções nativas
do Lua (como print, io, os, etc.)
para o código avaliado. Isso é intencional — garante que código de
terceiros não possa acessar arquivos ou executar comandos no seu
sistema.
Se você confia no código que vai executar e precisa dessas funções:
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
// ATENÇÃO: só use isso se você confiar no código que será executado!
// Isso dá acesso a print, io, os, e outras libs nativas do Lua.
LuaCEmbed_load_native_libs(l);
LuaCEmbed_evaluate(l, "print('hello from lua')");
if (LuaCEmbed_has_errors(l)) {
printf("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Saída:
hello from lua
Executando um arquivo .lua
Em vez de passar código como string, você pode carregar um arquivo
.lua do disco:
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_load_native_libs(l);
// Carrega e executa o arquivo "script.lua"
LuaCEmbed_evaluete_file(l, "script.lua");
if (LuaCEmbed_has_errors(l)) {
printf("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Callbacks — Expondo Funções C para o Lua
Callbacks são a forma de criar funções em C que podem ser chamadas a partir do código Lua. Isso permite que você defina exatamente o que o usuário pode ou não fazer.
Callback simples (sem argumentos, sem retorno)
#include "LuaCEmbedOne.c"
// Esta função C será chamável a partir do Lua
LuaCEmbedResponse *hello(LuaCEmbed *args) {
printf("meu primeiro callback\n");
return NULL; // NULL significa: não retorna nada (nil no Lua)
}
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
// Registra a função C com o nome "hello" no Lua
LuaCEmbed_add_callback(l, "hello", hello);
// Agora o código Lua pode chamar hello()
LuaCEmbed_evaluate(l, "hello()");
if (LuaCEmbed_has_errors(l)) {
printf("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Saída:
meu primeiro callback
Recebendo argumentos no callback
Os argumentos passados pelo Lua ficam disponíveis dentro da função C. Eles são indexados a partir de 0 (padrão C), mesmo que o Lua normalmente use índices a partir de 1.
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *test_func(LuaCEmbed *args) {
// Quantos argumentos foram passados?
long size = LuaCEmbed_get_total_args(args);
if (size == 0) {
printf("nenhum argumento fornecido\n");
return NULL;
}
// Lê o primeiro argumento (índice 0)
int index = 0;
int arg_type = LuaCEmbed_get_arg_type(args, index);
// Age de acordo com o tipo recebido
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 outros tipos (como tabela), mostra o nome do 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);
// Testa com diferentes tipos de argumento
LuaCEmbed_evaluate(l, "test()"); // sem 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})"); // tabela
if (LuaCEmbed_has_errors(l)) {
printf("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Saída:
nenhum argumento fornecido
número: 10.000000
string: hello
bool: 1
tipo: table
Retornando valores de um callback
Um callback pode retornar um valor para o Lua usando as funções
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);
// Se houve erro ao ler os argumentos (ex: tipo errado), propaga o erro
if (LuaCEmbed_has_errors(args)) {
return LuaCEmbed_send_error(LuaCEmbed_get_error_message(args));
}
return LuaCEmbed_send_double(a + b); // retorna a soma para o 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("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Saída:
resultado: 30.000000
Funções de retorno disponíveis:
| Função | Retorna |
|---|---|
LuaCEmbed_send_double(double) |
número decimal |
LuaCEmbed_send_long(long) |
número inteiro |
LuaCEmbed_send_str(char*) |
texto |
LuaCEmbed_send_bool(bool) |
verdadeiro/falso |
LuaCEmbed_send_table(LuaCEmbedTable*) |
tabela |
LuaCEmbed_send_error(char*) |
propaga um erro para o Lua |
return NULL |
nil (sem retorno) |
Tabelas
Tabelas são o principal tipo de dado estruturado do Lua — funcionam como arrays, dicionários e objetos ao mesmo tempo.
Lendo propriedades de uma tabela recebida
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *show_table(LuaCEmbed *args) {
// Lê o primeiro argumento como tabela
LuaCEmbedTable *t = LuaCEmbed_get_arg_table(args, 0);
if (LuaCEmbed_has_errors(args)) {
return LuaCEmbed_send_error(LuaCEmbed_get_error_message(args));
}
// Lê as propriedades pelo nome
char *name = LuaCembedTable_get_string_prop(t, "name");
long age = LuaCembedTable_get_long_prop(t, "age");
printf("nome: %s\n", name);
printf("idade: %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("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Saída:
nome: Mateus
idade: 27
Tamanho de uma tabela
#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("tamanho: %ld\n", size); // 3
LuaCEmbed_free(l);
return 0;
}Saída:
tamanho: 3
Iterando sobre os elementos de uma tabela
#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 se o elemento tem uma chave (string) associada
const char *key = "sem chave";
if (LuaCembedTable_has_key_at_index(t, i)) {
key = LuaCembedTable_get_key_by_index(t, i);
}
printf("chave: %s\n", key);
// Lê o tipo e o valor do 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("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Lendo sub-tabelas (tabelas dentro de tabelas)
#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 é uma tabela com "name" e "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("nome: %s, idade: %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("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Saída:
nome: Alice, idade: 30
nome: Bob, idade: 25
Criando e retornando uma tabela de C para Lua
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *create_table(LuaCEmbed *args) {
// Cria uma nova tabela vazia
LuaCEmbedTable *t = LuaCembed_new_anonymous_table(args);
// Define as propriedades
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);
// Retorna a tabela para o 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("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Saída:
Mateus 27 1.82 false
Adicionando métodos a uma tabela
Você pode criar tabelas que se comportam como objetos, com métodos chamáveis pelo Lua:
#include "LuaCEmbedOne.c"
// O método recebe a própria tabela como 'self' (como em orientação 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("nome: %s, idade: %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("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Saída:
nome: Mateus, idade: 27
Meta-métodos
Meta-métodos permitem interceptar operações especiais do Lua, como
acesso a propriedades (__index) e destruição pelo garbage
collector (__gc):
#include "LuaCEmbedOne.c"
// Chamado quando o Lua acessa uma propriedade da tabela
LuaCEmbedResponse *index_callback(LuaCEmbedTable *self, LuaCEmbed *args) {
int value_type = LuaCEmbed_get_arg_type(args, 1);
if (value_type == LUA_CEMBED_STRING) {
printf("acesso ao índice: %s\n", LuaCEmbed_get_str_arg(args, 1));
}
return NULL;
}
// Chamado quando o garbage collector do Lua destrói a tabela
LuaCEmbedResponse *gc_callback(LuaCEmbedTable *self, LuaCEmbed *args) {
printf("tabela destruída pelo 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("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Saída:
acesso ao índice: foo
tabela destruída pelo GC
Criando uma Biblioteca (.so/.dll)
Além de executar Lua a partir de C, você também pode criar o caminho
inverso: compilar C como uma biblioteca dinâmica e importá-la
diretamente do Lua com 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);
}
// O nome da função DEVE ser "luaopen_" + nome_da_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);
}Compile como biblioteca compartilhada:
gcc -shared -fPIC -o my_lib.so main.cUse em Lua:
local lib = require("my_lib")
print(lib.add(10, 20)) -- 30.0
print(lib.sub(20, 5)) -- 15.0Propriedades estáticas na biblioteca
Você também pode expor constantes e valores fixos:
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);
}Em Lua:
local lib = require("my_lib")
print(lib.version) -- 1
print(lib.author) -- MateusSegurança: Timeout e Limite de Memória
Quando você executa código enviado por usuários, é importante proteger seu programa contra loops infinitos e uso excessivo de memória.
Timeout
Interrompe a execução após um número de segundos:
#include "LuaCEmbedOne.c"
int main(int argc, char *argv[]) {
LuaCEmbed *l = newLuaCEmbedEvaluation();
LuaCEmbed_set_timeout(2); // interrompe após 2 segundos
LuaCEmbed_evaluate(l, "while true do end"); // loop infinito
if (LuaCEmbed_has_errors(l)) {
printf("erro: %s\n", LuaCEmbed_get_error_message(l));
}
// Após um timeout, você pode limpar o erro e continuar usando a instância
LuaCEmbed_clear_errors(l);
LuaCEmbed_evaluate(l, "r = 'ainda funciona'");
printf("%s\n", LuaCEmbed_get_evaluation_string(l, "r"));
LuaCEmbed_free(l);
return 0;
}Saída:
erro: timeout error
ainda funciona
Limite de Memória
Impede que o código Lua consuma memória sem controle (padrão: 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 tenta crescer uma string indefinidamente
LuaCEmbed_evaluate(l, "t = 'a'; while true do t = t .. t end");
if (LuaCEmbed_has_errors(l)) {
printf("erro: %s\n", LuaCEmbed_get_error_message(l));
}
LuaCEmbed_free(l);
return 0;
}Saída:
erro: not enough memory
Tratamento de Erros
Sempre verifique erros após avaliações. Se não verificar, erros silenciosos podem causar comportamentos inesperados.
#include "LuaCEmbedOne.c"
LuaCEmbedResponse *minha_funcao(LuaCEmbed *args) {
double val = LuaCEmbed_get_double_arg(args, 0);
if (LuaCEmbed_has_errors(args)) {
// Propaga o erro para o Lua em vez de continuar com 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("erro: %s\n", LuaCEmbed_get_error_message(l));
// Limpa o erro para continuar usando a mesma instância
LuaCEmbed_clear_errors(l);
}
LuaCEmbed_add_callback(l, "minha_funcao", minha_funcao);
double result = LuaCEmbed_get_evaluation_double(l, "minha_funcao(21)");
printf("resultado: %lf\n", result);
LuaCEmbed_free(l);
return 0;
}Saída:
erro: [string "código inválido %%%"]:1: unexpected symbol near '%'
resultado: 42.000000
Referência Rápida
| Função | Descrição |
|---|---|
newLuaCEmbedEvaluation() |
Cria uma nova instância |
LuaCEmbed_evaluate(l, code) |
Executa código Lua (string) |
LuaCEmbed_evaluete_file(l, path) |
Executa um arquivo Lua |
LuaCEmbed_load_native_libs(l) |
Habilita libs nativas (print, io, os…) |
LuaCEmbed_add_callback(l, name, fn) |
Registra uma função C no Lua |
LuaCEmbed_get_evaluation_string(l, expr) |
Lê resultado como string |
LuaCEmbed_get_evaluation_long(l, expr) |
Lê resultado como inteiro |
LuaCEmbed_get_evaluation_double(l, expr) |
Lê resultado como decimal |
LuaCEmbed_get_evaluation_bool(l, expr) |
Lê resultado como booleano |
LuaCEmbed_get_evaluation_type(l, expr) |
Retorna o tipo da expressão |
LuaCEmbed_get_evaluation_table_size(l, expr) |
Retorna o tamanho de uma tabela |
LuaCEmbed_has_errors(l) |
Verifica se houve erro |
LuaCEmbed_get_error_message(l) |
Obtém a mensagem de erro |
LuaCEmbed_clear_errors(l) |
Limpa o estado de erro |
LuaCEmbed_set_timeout(seconds) |
Define timeout de execução |
LuaCEmbed_set_memory_limit(l, mb) |
Define limite de memória em MB |
LuaCEmbed_free(l) |
Libera a instância |
