Anuncios

Bienvenidos sean a este post, hoy hablaremos sobre las funciones de C y como nuestro primer ejemplo veremos como implementar una version simplificada de una funcion que devuelve el seno de un numero informado:

static int l_sin(lua_State *L)
{
	double d = lua_tonumber(L, 1);
	lua_pushnumber(L, sin(d));
	return 1;
}
Anuncios

En este caso la funcion obtiene como argumento a la pila (L), luego obtiene el valor del argumento desde la pila con la primera linea, despues empujaremos a la pila el resultado de la operacion seno (sin) con el argumento obtenido (d), para finalmente devolver el numero de resultados, como cualquier funcion registrada con Lua debe tener este mismo prototipo definido como lua_CFunction en lua.h:

typedef int (*lua_CFunction) (lua_State *L);
Anuncios

Desde el punto de vista de C, una funcion de C consigue como su unico argumento el estado de Lua y devuelve un entero con el numero de valores que esta devolviendo en la pila, ademas la funcion no necesita limpiar la pila antes de empujar sus resultados, despues de devolverlo Lua automaticamente remueve lo que sea que este en la pila por debajo de los resultados, antes de que podamos usar esta funcion desde Lua debemos registrarla, para hacer esta pequeña magia usamos a lua_pushcfunction, consigue un apuntador para una funcion de C y crea un valor de tipo “function” que representa esta funcion dentro de Lua, una vez registrada una funcion de C se comporta como cualquier otra funcion dentro de Lua.

Anuncios

Una manera rapida y sencilla para testear l_sin es poner su codigo directamente dentro del archivo lua.c y se agrega las siguientes lineas justo despues de llamar a luaL_openlibs:

lua_pushcfunction(L, l_sin);
lua_setglobal(L, "mysin");
Anuncios

La primera linea empuja un valor de tipo funcion, la segunda linea lo asigna a la variable global mysin, despues de estas modificaciones recompilas tu ejecutable de Lua para luego usar la nueva funcion mysin en tu programa de Lua, para una funcion de seno mas profesional debemos chequear el tipo de argumento, en este caso la libreria auxiliar nos ayudara, la funcion luaL_checknumber chequea si el argumento informado es un numero, en caso de error lanza un mensaje de informacion de error, de lo contrario devuelve un numero, veamos la pequeña modificacion de nuestro codigo:

static int l_sin(lua_State *L)
{
	double d = luaL_checknumber(L, 1);
	lua_pushnumber(L, sin(d));
	return 1;
}
Anuncios

Con la definicion anterior si ejecutas:

mysin('a') 

Te devuelve este mensaje:

Bad argument #1 to 'mysin' (number expected, got string)
Anuncios

Observemos como luaL_checknumber automaticamente completo el mensaje con el numero de argumento (#1), el nombre de la funcion (“mysin”), el tipo de parametro esperado (number) y el tipo de parametro actual (string), veamos un ejemplo mas complejo.

Anuncios
Anuncios

Vamos a escribir una funcion que nos devuelve el contenido de un directorio informado, como Lua no provee esta funcion en su libreria estandar porque ANSI C no tiene funciones para este trabajo, para este caso vamos a asumir que tenemos un sistema compatible con POSIX, nuestra funcion (dir en Lua, l_dir en C) consigue como argumento una cadena con la ruta del directorio y devuelve un array con las entradas del directorio, por ejemplo si llamamos a:

dir("/home/tinchicus") 

Nos puede devolver una tabla:

{ ".","..","src","bin","lib"}
Anuncios

En caso de error la funcion devuelve un valor nil ademas de una cadena con el mensaje de error, el codigo completo para esta funcion es el siguiente:

#include <dirent.h>
#include <errno.h>

static int l_dir(lua_State *L)
{
	DIR *dir;
	struct dirent *entrada;
	int i;
	const char *path = luaL_checksring(L, 1);

	dir = opendir(path);
	if (dir == NULL)
	{
		lua_pushnil(L);
		lua_pushstring(L, strerror(errno));
		return 2;
	}

	lua_newtable(L);
	i = 1;
	while((entrada = readdir(dir)) != NULL)
	{
		lua_pushnumber(L, i++);
		lua_pushstring(L, entrada->d_name);
		lua_settable(L, -3);
	}

	closedir(dir);
	return 1;
}
Anuncios

Observemos el uso de la funcion luaL_checkstring de la libreria auxiliar la cual es equivalente a la funcion que mencionamos antes, luaL_checknumber, pero en este caso para cadenas, en condiciones extremas esta implementacion de l_dir podria causar una pequeña perdida de memoria, tres de las funciones de Lua que se llama pueden fallar debido a memoria insuficiente:

  • lua_newtable
  • lua_pushstring
  • lua_settable
Anuncios

Si cualquiera de estas funciones falla, creara un error e interrumpira a l_dir, la cual impedira que se llame a closedir, como discutimos anteriormente en muchos programas no es un gran problema si el programa se queda sin memoria, lo mejor que se puede hacer es apagarlo de cualquier forma, sin embargo en otro post mas adelante veremos una implementacion alternativa para una funcion de directorio para evitar este problema.

Anuncios

En resumen, hoy hemos visto como crear una funcion de C para ser implementada en Lua, un ejemplo sencillo, una mejor version de este ejemplo con ayuda de la libreria auxiliar, otro ejemplo implementando la libreria auxiliar tambien, hemos comentado que inconveniente nos puede generar y cuales son las probables funciones que fallen, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00