lua學習筆記之userdata


  這一段時間看了《programming in lua》中的第28章,看一遍並不是很難,但是只是朦朧的感覺,霧里看花,水中望月。最終還是決定敲出來自己看看,練練手,結果受益不少,也遇到了一些問題,記在這里。自己做一個總結,也希望能幫助和我一樣lua的初學者。

1. 書上並沒有寫清楚對於CAPI的制作和使用內容。主要包括dll的生成,以及使用

(1)dll生成。

  直接用vs新建一個dll工程,要記得包含依賴路徑。如下圖所示,包含你的lua安裝路徑。

  工程名要和庫的最終名字一致(默認是一致的)。luaopen_array(lua_State *L)也最好一致。這一塊,我沒有去研究和測試,就是按照書上來做的,沒有碰到什么大的問題,主要和使用方式有一些關系。

(2)使用

兩種方法:

第一種:require "myarray"。這就需要dll的名字是myarray.dll。而且luaopen_xxx(lua_State *L)也是luaopen_array的形式;

第二種:package.loadlib("array", "luaopen_array")()。這種的話,第一個參數array是你在寫c代碼時候注冊的table名字,后面一個函數名。這種使用方式我個人覺得是需要dll名字以及注冊的table名必須是"array",但是luaoepn_xxx就不需要了。

(3)linux

  直接使用命令:gcc mylib.c -fPIC -shared -o libmylib.so即可生成可以使用的動態庫。

  使用和window下面的使用一樣,自己用的是第二種方法:package.loadlib("./libmydir.so", "luaopen_mydir")()

2. 一些問題

(1)直接使用loadlib不行

  mylib = loadlib("mylib", "luaopen_mylib")

解決:加上庫,package.loadlib

(2)使用package.loadlib的時候報錯

描述:lua: capi_study.lua:57: attempt to call a nil value

原因:工程名字生成的庫名字和使用的時候不一致出錯

(3)luaL_openlib和luaL_register

  *接口變化,我用的lua版本是5.1.所以用luaL_register接口,而不是書上仍然使用的luaL_openlib接口。官網的document的5.1《reference manual》中有提到,可以自己去看。

  *linux卻仍然還是需要使用前者。(linux下面的版本是5.2.0了,不明白是什么原因)

(4)面向對象例子報錯

描述:lua: capi_study.lua:102: calling 'size' on bad self (luaBook.array expected, got userdata)

原因:void *ud = luaL_checkudata(L, 1, "LuaBook.array");中的"LuaBook.array"寫成了"luaBook.array"

 結果:Success!

package.loadlib("array", "luaopen_array")()
a = array.new(1000)
print(a:size())
a:set(10, 3.4)
print(a:get(10))

輸出結果:

1000
3.4

(5)linux編譯報錯

描述:“錯誤:數組元素的類型不完全”

原因:

*用gcc4編譯時出現數組元素的類型不完全錯誤,這是因為gcc4不允許類型在聲明前使用。【引用:http://blog.csdn.net/horsefaced/article/details/1678965】

*luaL_Reg寫成了luaL_reg

解決:

(6)linux編譯警告

描述:警告:傳遞參數 2 (屬於 ‘lua_getmetatable’)時將指針賦給整數,未作類型轉換

原因:低級錯誤luaL_getmetatable寫成了lua_getmetatable,希望碰到這個問題的能夠不用再糾結了

3.一個例子

  附上dir例子的源碼,linux編譯通過。

#include <math.h>
#include <dirent.h>
#include <errno.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

/* forward declaration */
static int dir_iter(lua_State *L);

static int l_dir(lua_State *L){
        const char *path = luaL_checkstring(L, 1);

        /* create a userdatum */
        DIR **d = (DIR **)lua_newuserdata(L, sizeof(DIR *));

        /* set its metatable */
        luaL_getmetatable(L, "LuaBook.dir");
        lua_setmetatable(L, -2);

        /* try to pen then given dirctory */
        *d = opendir(path);
        if (*d == NULL)
        luaL_error(L, "cannot open %s: %s", path, strerror(errno));

        /* creates and returns the iterator function */
        lua_pushcclosure(L, dir_iter, 1);
        return 1;
}

static int dir_iter(lua_State *L){
        DIR *d = *(DIR **)lua_touserdata(L, lua_upvalueindex(1));
        struct dirent *entry;
        if (( entry = readdir(d)) != NULL){
                lua_pushstring(L, entry->d_name);
                return 1;
        }
        else return 0;  /* no more valuse to return */
}

static int dir_gc(lua_State *L){
        DIR *d = *(DIR **)lua_touserdata(L, 1);
        if (d) closedir(d);
        return 0;
}

int luaopen_mydir (lua_State *L){
        luaL_newmetatable(L, "LuaBook.dir");

        /* set its __Gc field */
        lua_pushstring(L, "__gc");
        lua_pushcfunction(L, dir_gc);
        lua_settable(L, -3);

        /* register the 'dir' function */
        lua_pushcfunction(L, l_dir);
        lua_setglobal(L, "dir");

        return 0;
}

 使用和結果

> package.loadlib("./libmydir.so", "luaopen_mydir")()
> for fname in dir(".") do print(fname) end
.
..
libmylib.so
libdir.so
dir.c
.dir.c.swp
dir.so
mydir_none.c
mylib.c
libmydir.so
mydir.c
capi_study.lua
lua-5.1.2
> 

 

 

4. 總結

(1)lua調用c函數,返回的就是棧上的內容。例如:你在c函數壓入一個整數,那么返回的第一個就是這個整數。

(2)linux命令:gcc mylib.c -fPIC -shared -o libmylib.so

(3)看書學習的時候,當覺得朦朧不清晰的時候,要放慢速度,最好的就是Do it。敲出來去看看,會有不同的收獲,感覺有東西,這種感覺個人覺得是學習的時候最好的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM