2010-12-01 50 views
22
  • Qu'est-ce que userdata et lightuserdata dans Lua?
  • Où en ai-je besoin?

J'ai essayé de m'en tenir à la tête depuis un certain temps maintenant, mais je n'arrive pas à trouver de tutoriels/explications que je comprenne vraiment. Pourquoi avez-vous besoin d'eux, pourquoi ne pouvez-vous pas directement lier directement les fonctions C aux métabalyses Lua?Qu'est-ce que userdata et lightuserdata dans Lua?

+1

Une méta-donnée doit être attachée à * quelque chose *, une userdatum est un choix raisonnable. – Textmode

Répondre

7

Eh bien, les données d'utilisateur sont des données du côté C qui peuvent être utilisées depuis Lua. Tels que par exemple les handles de fichiers comme io.input sont userdata (essayez print (type (io.input))). Vous en aurez besoin vous-même si vous commencez à vous tromper avec le Lua C-API (ou utilisez la fonction newproxy, qui vous donne un userdatum vide, sur lequel vous pouvez définir un metatable (voir Fonctionnalités cachées http://lua-users.org/wiki/HiddenFeatures) sur le wiki Lua-users).

Une bonne introduction est: http://www.lua.org/pil/28.html

En ce qui concerne la substance des fonctions C: oui, vous pouvez simplement enregistrer des fonctions C comme des fonctions à appeler à l'intérieur Lua, mais il ne vous obtenir d'autres types de données, des pointeurs à des données sur le côté C, etc.

2

Vous pouvez utiliser userdata Chaque fois que vous avez une quantité de données que vous voulez être géré par le lua gc. Par exemple, vous pouvez l'utiliser pour les objets C++. Quelques exemples pour C++ - objets avec userdata: Vous pouvez en enregistrer un dans userdata, vous pouvez l'oublier en C++ car il sera géré par lua. Vous pouvez donc le référencer dans luavariables et le passer aux fonctions qui appellent une fonction member de l'objet C++. (il y a des façons de généraliser cela bien sûr comme mettre un objet fonction générique dans les données utilisateur, lier cela comme valeur élevée à une fermeture C et enregistrer cette fermeture c sur un luaobject qui représente le côté lua de l'objet C++, implique également userdata). Si vous ne voulez pas que lua gc gère vos objets et que vous souhaitiez simplement référencer votre objet C++ depuis lua, vous pouvez y stocker un pointeur en tant que données utilisateur légères.

42

Une donnée d'utilisateur est une valeur collectée par la corbeille d'une taille et d'un contenu arbitraires. Vous en créez un à partir de l'API C, avec lua_newuserdata(), qui le crée et le pousse sur la pile et vous donne un pointeur sur son contenu pour l'initialiser comme vous le souhaitez.

Il est très comparable à l'appel malloc(). Une distinction clé par rapport à malloc() est que vous n'avez jamais besoin d'appeler free(), vous autorisez simplement la dernière référence à s'évaporer et le garbage collector va récupérer son stockage.

Elles sont très utiles pour conserver des données utiles à partir de C, mais qui doivent être gérées à partir de Lua. Ils prennent en charge les métadonnées individuelles, qui sont la fonctionnalité clé permettant de lier des objets C ou C++ à Lua. Vous remplissez simplement sa metatable avec des méthodes écrites en C qui accèdent, modifient et/ou utilisent le contenu des données utilisateur, et le résultat est un objet accessible depuis Lua. Un bon exemple de ceci est le io library, qui stocke les pointeurs C FILE * dans userdata, et fournit des liaisons qui implémentent les méthodes familières read, write et similaires. En implémentant un métaméthode __gc, la bibliothèque io s'assure qu'un de ses objets file ferme le FILE * associé lorsqu'il est collecté. Un léger userdata est comment vous représentez un pointeur vers quelque chose comme une valeur dans Lua. Vous en créez un en appelant le lua_pushlightuserdata() avec le pointeur correspondant à sa valeur.Ils sont gérés par Lua de la même manière qu'un certain nombre. Ils sont utiles lorsque vous devez nommer un objet C de telle sorte que le nom puisse être transmis dans Lua, mais la durée de vie de l'objet n'est pas gérée par Lua. Les nombres identiques sont égaux lorsqu'ils ont la même valeur, les données userdata légères sont égales lorsqu'elles contiennent le même pointeur. Comme les nombres, ils existent aussi longtemps qu'ils sont sur la pile ou stockés dans une variable, et ils n'ont pas de métabalies individuelles et ils ne sont pas collectés.

+0

+1 pour la description détaillée de la gestion de la mémoire :) – Eonil

1

D'abord, userdata signifie données utilisateur complètes. Voici deux solutions pour implémenter CharArray. S'il vous plaît voir ci-dessous:

//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; 
} 

userdata pleine est une zone de mémoire brute sans opérations prédéfinies qui offre de Lua. Donc userdata doit être géré par le garbage collector. D'autre part, léger userdata est juste une valeur qui représente un pointeur C (c'est-à-dire, une valeur void *). Les données utilisateur légères n'ont pas besoin d'être gérées par le garbage collector (et ne le sont pas).