欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

lua調(diào)用C/C++的方法詳解

 更新時間:2023年10月07日 09:16:00   作者:luofengmacheng  
lua是腳本語言,優(yōu)點是門檻低,可以熱更新,缺點當(dāng)然就是性能,C/C++是編譯型語言,有點是性能高,但是相對的,門檻高,lua語言本身就是用C實現(xiàn)的,而且,可以將很多能力封裝成lua的接口供lua調(diào)用,本文將給大家介紹lua如何調(diào)用C/C++,需要的朋友可以參考下

1 lua vs C/C++

lua是腳本語言,優(yōu)點是門檻低,可以熱更新,缺點當(dāng)然就是性能。C/C++是編譯型語言,有點是性能高,但是相對的,門檻高,技術(shù)不好的人寫的代碼可能還沒有l(wèi)ua的性能高,容易出現(xiàn)core,不能熱更新。

不過,lua語言本身就是用C實現(xiàn)的,而且,可以將很多能力封裝成lua的接口供lua調(diào)用。

2 C/C++如何給lua提供接口

查看一個lua模塊的源代碼會發(fā)現(xiàn),lua模塊的實現(xiàn)中既包含lua代碼,也包含C代碼,其中,C代碼的主要邏輯就是獲取參數(shù),調(diào)用系統(tǒng)調(diào)用,返回值,C代碼會編譯為so供lua調(diào)用,而lua代碼就是將C代碼提供的一些接口進行再封裝,以便在lua中更好用,更簡單,然后再通過lua代碼對外提供接口。因此,這么看起來,通過lua調(diào)用C函數(shù),重要的就是在C中如何獲取參數(shù)以及如何返回值。

下面的說明以linotify項目進行說明。

2.1 lua模塊的查找

當(dāng)在lua里面通過require(“inotify”)時,lua怎么知道去哪里查找inotify模塊呢?此時,inotify模塊是個lua腳本還是個so呢?

跟其他腳本語言類似,lua中也是通過變量來控制模塊的查找的,其中package.path是搜索lua模塊的路徑,package.cpath是搜索so模塊的路徑,先查找lua模塊,再查找so模塊。

通過上面這種方式,在當(dāng)前目錄找到了inotify.so。

2.2 so的入口

要調(diào)用inotify.so中的函數(shù),肯定還是要用動態(tài)庫的函數(shù):dlopen、dlsym。例如,當(dāng)調(diào)用require(“inotify”)時,如果沒有導(dǎo)入inotify.so,則調(diào)用dlopen加載inotify.so庫,

當(dāng)在lua中調(diào)用local wd = handle:addwatch('/home/rob/', inotify.IN_CREATE, inotify.IN_MOVE)時,會調(diào)用handle_add_watch()函數(shù)。

2.3 參數(shù)獲取

lua和C之間是通過棧進行交互的,當(dāng)調(diào)用C函數(shù)時,C函數(shù)的第一個參數(shù)是lua_State的指針,可以將它理解為lua的一個狀態(tài)機。

如果要調(diào)用函數(shù),第一步就是參數(shù)的獲取,lua會將參數(shù)放到棧中,因此,inotify.so中的函數(shù)可以獲取棧中的數(shù)據(jù)得到參數(shù):

    fd = get_inotify_handle(L, 1);
    path = luaL_checkstring(L, 2);
    top = lua_gettop(L);
    for (i = 3; i <= top; i++) {
        mask |= (uint32_t)luaL_checkinteger(L, i);
    }

get_inotify_handle()獲取棧中的第1個參數(shù),luaL_checkstring(L, 2)獲取棧中的第2個參數(shù),且第2個參數(shù)是個字符串,然后通過lua_gettop(L)獲取所有的參數(shù)的個數(shù),再用for循環(huán)將剩余的參數(shù)通過位或放到mask變量。通過這種方式就分別得到了addwatch()的三個參數(shù)。

然后再調(diào)用inotify的inotify_add_watch()完成實際的邏輯。

2.4 返回值

當(dāng)具體的業(yè)務(wù)邏輯完成后,就需要將返回值傳給lua,依舊是通過入棧的方式。

在這里,調(diào)用完inotify_add_watch()就得到某個監(jiān)聽操作的描述符,也需要將這個描述符返回,如果操作成功,調(diào)用lua_pushinteger(L, wd)將wd返回,如果操作失敗,則返回3個值:

static int handle_error(lua_State *L)
{
    lua_pushnil(L);
    lua_pushstring(L, strerror(errno));
    lua_pushinteger(L, errno);
    return 3;
}

第1個是nil,第2個是錯誤信息,第3個是錯誤碼。

因此,在lua中可以這樣來調(diào)用:

local wd, err_info, errno = handle:addwatch('/home/rob/', inotify.IN_CREATE, inotify.IN_MOVE)
if wd == nil then
    print("ERROR=", err_info)
end

同時還需要注意handle_add_watch()函數(shù)的返回值,返回值表明了lua中函數(shù)返回值的個數(shù)。例如這里,成功時,只返回描述符,因此,函數(shù)返回值是1,失敗時,多了額外的錯誤信息,因此,函數(shù)返回值是3。

2.5 一個小的demo

有了上面的了解,可以實現(xiàn)我們的一個小小的demo。

假設(shè)我們要實現(xiàn)一個加法操作,實際的加法操作在C中完成,然后在lua中調(diào)用。

#include <lua.h>
#include <lauxlib.h>
static int handle_add(lua_State *L) {
	int a, b, c;
	a = luaL_checkinteger(L, 1);
	b = luaL_checkinteger(L, 2);
	c = a + b;
	lua_pushinteger(L, c);
	return 1;
}
static luaL_Reg funcs[] = {
	{"add", handle_add},
	{NULL, NULL}
};
int luaopen_demo(lua_State *L) {
	lua_createtable(L, 0, sizeof(funcs)/sizeof(luaL_Reg) - 1);
	luaL_setfuncs(L, funcs, 0);
	return 1;
}

那這里的入口函數(shù)就是luaopen_demo(),里面就調(diào)用了兩個函數(shù),先調(diào)用lua_createtable創(chuàng)建

將上面的代碼編譯為so:

gcc demo.c -fPIC -shared -o demo.so

lua中調(diào)用:

local demo = require("demo")
print(demo.add(2, 3))

3 lua FFI

lua C API實現(xiàn)lua的模塊使用的是虛擬棧的方式,實現(xiàn)起來太過麻煩,用戶需要使用一種新的接口(C API)和模式(虛擬棧)實現(xiàn),而使用FFI機制,就可以在lua中直接調(diào)用C函數(shù)。

3.1 一個小例子

local ffi = require("ffi")
ffi.cdef[[
int printf(const char*fmt, ...);
]]
ffi.C.printf("hello %s", "world");

首先加載ffi模塊,然后使用cdef添加C函數(shù)的聲明,有點類似于C語言中的頭文件,然后就可以調(diào)用ffi.C中的printf函數(shù)。然后就可以使用luajit編譯:luajit hell.lua。

3.2 調(diào)用so

上面的例子是調(diào)用C標準庫中的函數(shù),如果需要調(diào)用其他的so文件呢?

// libtest.c
#include <stdio.h>
int show(char *str) {
	int ret = 0;
	if(str == NULL) {
		ret = -1;
	} else {
		printf("input: %s\n", str);
	}
	return ret;
}
# 將上述代碼編譯為so
gcc -shared -fPIC libtest.c -o libtest.so

然后就可以在lua中調(diào)用:

local ffi = require("ffi")
-- 加載libtest.so
local myffi = ffi.load("test")
-- 聲明函數(shù)原型
ffi.cdef[[
int show(char *str);
]]
local str1 = "hello"
-- 將字符串類型轉(zhuǎn)換為char*
local str2 = ffi.cast("char *",str1)
-- 調(diào)用libtest.so中的show函數(shù)
print(myffi.show(str2))

4 C API vs FFI

FFI相比C API最大的優(yōu)勢就是比較好理解,性能高,但是使用FFI也存在一些兼容性的問題;而C API由于是官方提供的接口,在穩(wěn)定性方面還是很好的。

5 參考文檔

以上就是lua調(diào)用C/C++的方法詳解的詳細內(nèi)容,更多關(guān)于lua調(diào)用C/C++的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • lua開發(fā)中實現(xiàn)MVC框架的簡單應(yīng)用

    lua開發(fā)中實現(xiàn)MVC框架的簡單應(yīng)用

    最近的游戲項目中使用了lua腳本來開發(fā),項目中用到了MVC框架,最近有朋友問我怎么弄,在這里簡單分享一下思路和一些開發(fā)中的技巧。有需要的小伙伴可以參考下。
    2015-04-04
  • Lua的函數(shù)環(huán)境、包實例講解

    Lua的函數(shù)環(huán)境、包實例講解

    這篇文章主要介紹了Lua的函數(shù)環(huán)境、包實例講解,本文分別對函數(shù)環(huán)境、包的定義、實現(xiàn)方式、使用方式做了分解,需要的朋友可以參考下
    2014-09-09
  • 最新評論