2010-12-01 23 views
22
  • ¿Qué es userdata y lightuserdata en Lua?
  • ¿Dónde lo necesito?

He estado tratando de entender esto desde hace un tiempo, pero parece que no puedo encontrar ningún tutorial/explicación que realmente entiendo.¿Qué es userdata y lightuserdata en Lua?

¿Por qué los necesitas? ¿Por qué no puedes unir directamente las funciones C a las metatablas Lua?

+1

Se debe adjuntar un metatabla a * algo *, un userdatum es una opción razonable. – Textmode

Respuesta

7

Bueno, los datos de usuario son datos del lado C que se pueden usar desde dentro de Lua. Por ejemplo, los identificadores de archivos como io.input son userdata (prueba print (type (io.input))). Lo necesitarás si empiezas a jugar con la Lua C-API (o usas la función newproxy, que te da un userdatum vacío, sobre el cual puedes establecer una metatabla (ver Funciones ocultas http://lua-users.org/wiki/HiddenFeatures) en la wiki de Lua-users)

Una buena introducción es: http://www.lua.org/pil/28.html

En cuanto a las cosas de funciones C: sí sólo se puede registrar funciones como funciones C a llamarse desde Lua, pero no obtendrá otros tipos de datos, punteros a los datos en el lado C, etc. etc.

2

puede usar userdata Siempre que tenga cierta cantidad de datos que desea, los puede gestionar el lua gc. Por ejemplo, podría usarlo para objetos C++. Algunos ejemplos de C++: objetos con datos de usuario: puede guardar uno en userdata, luego puede olvidarse en C++, ya que será administrado por lua. De modo que podría hacer referencia a él en luavariables y pasarlo a funciones que llaman a una función miembro del objeto C++. (hay formas de generalizar eso, por supuesto, como poner un objeto de función genérico en los datos de usuario, vincularlo como valor ascendente a un cierre C y registrar ese cierre c en un objeto lua que represente el lado lua del objeto C++, involucra userdata también). Si no desea que lua gc administre sus objetos y solo quiere hacer referencia a su objeto C++ desde lua, puede guardar un puntero como datos de usuario ligeros.

42

Un userdata es un valor recolectado de basura de un tamaño y contenido arbitrario. Se crea uno de la API C, con lua_newuserdata(), que crea y lo empuja en la pila y le da un puntero a su contenido para inicializar como mejor le parezca a partir de C.

Es muy comparable a llamar malloc(). Una distinción clave de malloc() es que nunca necesita llamar al free(), sino que simplemente permite que la última referencia se evapore y el recolector de basura recuperará su almacenamiento eventualmente.

Son más útiles para almacenar datos que son útiles desde C, pero que deben ser administrados desde Lua. Admiten metatablas individuales, que son la característica clave que permite unir objetos C o C++ a Lua. Simplemente llene su metatabla con métodos escritos en C que acceden, modifican y/o utilizan el contenido de los datos del usuario, y el resultado es un objeto al que se puede acceder desde Lua. Un buen ejemplo de esto es el io library, que almacena punteros C FILE * en userdata, y proporciona enlaces que implementan los conocidos read, write y métodos similares. Al implementar un meta-método __gc, la biblioteca io se asegura de que uno de sus objetos file cierre el FILE * asociado cuando se recopila.

Un userdata de luz es la forma en que representa un puntero a algo como un valor en Lua. Crea uno llamando al lua_pushlightuserdata() con el puntero que es su valor.Lua los maneja de la misma manera que un número. Son útiles cuando necesita nombrar un objeto C de forma que el nombre pueda transmitirse dentro de Lua, pero la vida del objeto no es administrada por Lua. Los números similares son iguales cuando tienen el mismo valor, los datos de usuario livianos se comparan iguales cuando tienen el mismo puntero. Como los números, existen siempre que estén en la pila o almacenados en una variable, y no tienen metatablas individuales y no son basura.

+0

+1 para obtener detalles sobre la gestión de la memoria :) – Eonil

1

Primero, userdata significa datos de usuario completos. Aquí hay dos soluciones para implementar CharArray. Por favor, ver más abajo:

//full userdata 
extern "C" int newarray(lua_State* L) 
{ 
    int n = luaL_checkint(L, 1); 
    size_t nbytes = sizeof(CharArray) + (n - 1)*sizeof(char); 
    CharArray* a = (CharArray*)lua_newuserdata(L, nbytes); 
    a->size = n; 
    return 1; 
} 

//light userdata 
extern "C" int newlarray(lua_State* L) 
{ 
    int n = luaL_checkint(L, 1); 
    size_t nbytes = sizeof(CharArray) + (n - 1)*sizeof(char); 
    CharArray* a = (CharArray*)(new char(nbytes)); 

    lua_pushlightuserdata(L,a); 
    a->size = n; 

    return 1; 
} 

datos de usuario completa es un área de memoria en bruto sin operaciones predefinidas que ofrece desde Lua. Por lo tanto, userdata debe ser administrado por el recolector de basura. Por otro lado, los datos de usuario light son solo un valor que representa un puntero C (es decir, un valor nulo *). Los userdata ligeros no necesitan ser gestionados por el recolector de basura (y no lo son).