1. 程式人生 > >lua與C/C++互調函式方法

lua與C/C++互調函式方法

luaC/C++互調函式方法

1.在lua指令碼中呼叫C/C++程式碼中的函式

C/C++函式定義形式

       lua中呼叫的C++函式的定義必須滿足如下形式: typedef int(*lua_cFunction)(lua_State *L);

       函式引數必須是lua_State,返回值必須是int型,只有這樣的函式Lua才能呼叫。

C函式引數獲取設定協議

      C函式中的引數通過Lua中堆疊L來接收到,引數以正序入棧,第一個引數首先入棧。第一個引數的索引是1,最後一個引數的索引就是引數個數。C函式剛開始處,沒有進行棧中資料pop、push操作之前,lua_gettop(L)可以返回函式接收到的引數個數。

C函式向lua中返回值

      需要向lua返回值,可以通過把需要返回的值以正序方式壓入棧即可(第一個返回值首先壓入)。

C函式的返回值

     C函式的返回值(int型別)= C函式向lua中返回的值個數(壓入棧的變數個數)

例子

     接收若干數字引數,並返回它們的平均數與和:

#include 
 
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include  // lua是用純C語言寫的
#include 
#include 
#ifdef __cplusplus
}
#endif /* __cplusplus */
 
int c_average(lua_State* L)
{
   int n = lua_gettop(L); /* 返回棧頂元素的索引。因為索引是從1開始編號的(1表示棧底,-1表示棧頂),所以這個結果等於堆疊上的元素個數(返回0表示堆疊為空)。這裡棧中元素的個數就是傳入的引數個數 */
   double sum = 0;
   int i;
 
   for (i = 1; i <= n; i++)
    {
       if (!lua_isnumber(L, i))
       {
           lua_pushstring(L, "Incorrect argument to 'average'"); // 將錯誤資訊壓入棧中
           lua_error(L); // 丟擲棧頂的錯誤
           /*
           int lua_error (lua_State *L);
           產生一個 Lua 錯誤。錯誤資訊(實際上可以是任何型別的 Lua 值)必須被置入棧頂。這個函式會做一次長跳轉,它不會再返回。
           */
       }
       sum += lua_tonumber(L, i); // lua_tonumber 將棧中指定index的值轉換成數值型別的值,注意並不會從棧中彈出這個值
    }
 
   double avg = sum / n;
   lua_pushnumber(L, avg); // 將avg壓入棧中,第1個返回值是avg
   lua_pushnumber(L, sum); // 將sum壓入棧中,第2個返回值是sum
 
   return 2; /* return the number of results,該函式有2個返回值,即上面入棧的avg和sum */
}


int main(int argc, char* argv[])
{
   lua_State* L = luaL_newstate(); // 建立一個新的獨立的狀態機
   
   /* register our function,告訴lua指令碼其中呼叫的average函式(lua中的變數名)對應的是一個叫c_average的c語言函式 */
   lua_register(L, "average", c_average);
   /*
   void lua_register (lua_State *L,
   const char *name,
   lua_CFunction f);
    把 C 函式 f 設到全域性變數 name 中。它通過一個巨集定義:
   #define lua_register(L,n,f) \
   (lua_pushcfunction(L, f), lua_setglobal(L, n))
   */
 
   /* run the script */
   luaL_dofile(L, "e1.lua"); // 載入指令碼,指令碼中的可執行語句將會得到執行
   
   /* Loads a file as a Lua chunk and then 以保護模式呼叫一個函式,等價於(luaL_loadfile(L,filename) || lua_pcall(L, 0, LUA_MULTRET, 0)) */
   lua_getglobal(L, "avg"); // 將全域性變數avg的值入棧,等價於lua_getfield(L,LUA_GLOBALSINDEX, "name”);此時el.lua中avg變數已經有值,等於把這個變數的值壓入棧。
   printf("avg is: %d\n", lua_tointeger(L, -1)); // 讀棧頂的int值,注意不會從棧中彈出這個元素
   lua_pop(L, 1); // 彈出棧頂的一個元素
   
   lua_getglobal(L, "sum"); // 將全域性變數sum的值入棧
   printf("sum is: %d\n", lua_tointeger(L, -1));
   lua_pop(L, 1); // 彈出棧頂的一個元素
   
   /* cleanup Lua */
   lua_close(L);
 
   return 0;
}
/*
-- e1.lua
avg, sum = average(10, 20, 30, 40, 50)
print("The average is ", avg)
print("The sum is ", sum)
*/
/*
輸出:
The average is  30
The sum is      150
avg is: 30
sum is: 150
*/

2.在C/C++程式碼中呼叫lua指令碼中的函式

      核心步驟:在C/C++中將使用的lua函式名以及其函式引數一次壓入棧中(引數按正序入棧),返回值由lua按正序自動壓入棧供C/C++訪問。函式呼叫成功後,函式名、引數出棧,返回值自動入棧(不需要手動寫壓入棧程式碼)

示例:

#include 
 
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include  // lua是用純c語言寫的
#include 
#include 
#ifdef __cplusplus
}
#endif /* __cplusplus */
 
lua_State* L = NULL;
 
int luaAdd(int x, int y)
{
   int sum;
 
   /* the function name,lua指令碼中的函式名 */
   lua_getglobal(L, "add"); // lua函式名入棧
 
   int savedTop = lua_gettop(L); // 儲存棧中的元素個數,後面要還原
 
   /* the first argument */
   lua_pushnumber(L, x); // 引數x入棧
   /* the second argument */
   lua_pushnumber(L, y); // 引數y入棧
 
   // 此時棧中有3個值,棧頂是引數y,棧底是函式名add
   /* call the function with 2 arguments, return 1 result */
   lua_call(L, 2, 1);
 
   // 因為add只有一個返回值,所以此時棧中只有1個值(如果有多個返回值,也是按正序入棧)
   /* get the result */
   sum = (int) lua_tonumber(L, -1); // -1是棧頂

   lua_settop(L, savedTop); // 函式退出之前恢復原來的棧
   return sum;
}
 
int main(int argc, char* argv[])
{
    L= luaL_newstate(); // 建立lua執行環境
   /* load the script,載入指令碼,為後面讀取其中的變數做準備 */
   luaL_dofile(L, "e2.lua");
   /* call the add function */
   int sum = luaAdd(10, 15);
   /* print the result */
   printf("The sum is %d\n", sum);
   /* cleanup Lua */
   lua_close(L);
   return 0;
}

-- e2.lua
-- add two numbers
function add(x, y)
   return x + y
end
 



The sum is 25

3. LUAJIT_MODE_ON

lua_pushlightuserdata(m_luastack, (void*) script_exception_wrapper);

luaJIT_setmode(m_luastack, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON);

int script_exception_wrapper(lua_State *L, lua_CFunction f)

{

try {

return f(L);  // Call wrapped function and return result.

} catch (constchar *s) {  // Catch and convert exceptions.

lua_pushstring(L, s);

} catch (LuaError& e) {

lua_pushstring(L, e.what());

}

returnlua_error(L);  // Rethrow as a Lua error.

}

LUAJIT_MODE_ON時,執行lua中函式,當呼叫C/C++函式時,會跳到script_exception_wrapper然後通過f(L)再跳到lua函式名對應的CFuntion;此模式必須使用lua_pushlightuserdata同時執行一個script_exception_wrapper指標函式;包裝器功能可以用於除錯目的,也可以用於捕獲和轉換外部異常。建議使用

lightuserdata使用時,只儲存了函式指標,不需要儲存真實資料,減少了記憶體使用。

LUAJIT_MODE_OFF時,執行lua中函式,當呼叫C/C++函式時,會直接跳到lua函式名對應的CFuntion;

參考資料:

http://blog.csdn.net/rain_qingtian/article/details/44781183

http://blog.csdn.net/ly131420/article/details/8794615

http://luajit.org/ext_c_api.html

http://dev.minetest.net/Script_Engine

相關推薦

luaC/C++調函式方法

lua與C/C++互調函式方法 1.在lua指令碼中呼叫C/C++程式碼中的函式 C/C++函式定義形式        lua中呼叫的C++函式的定義必須滿足如下形式: typedef int(*lua_cFunction)(lua_State *L);  

C/C++lua調函式方法

1,在lua指令碼中呼叫C/C++程式碼中的函式 在C++中定義函式時必須以lua_State為引數, 以int為返回值才能被Lua所呼叫。 /* typedef int (*lua_CFunction) (lua_State*L); C 函式的型別。 為了正確的和 Lu

golang go語言C語言調,通過cgo

1. good links: http://tonybai.com/2012/09/26/interoperability-between-go-and-c/ http://www.mischiefblog.com/2014/06/26/example-cgo-golang

C#呼叫C帶回調函式方法的實現

1、C語言定義個回撥函式的註冊 typedef void(__stdcall *test_callback)(int* array, int size); __declspec(dllexport)

C++ 編寫回調函式步驟

簡單幾步驟 void callback_func(void *userdata, const char*, uint32_t len) { //回撥函式內容 } typedef void(*ca

js字元ASCII碼轉的方法

大寫字母A-Z對應的ASCII碼值是65-90 小寫字母a-z對應的ASCII碼值是97-122 將字母轉為ascii嘛的方法: var str = "A"; str.charCodeAt(); // 65 var str1 = 'a'; str1.charCodeAt()

iOS原生介面RN介面調及傳值

文章目錄 3. iOS原生與RN互調及傳值 3.1 RN跳轉原生介面 3.2 RN跳轉原生介面並傳值 3.3 RN跳轉原生介面並傳值後,原生介面再回調給RN介面相關資訊 3. 4. 原生頁面向RN頁面傳值

c#後臺呼叫前臺js方法調

很多人都向在伺服器端呼叫客戶端的函式來操作,也就是在asp中呼叫javascript指令碼中已經定義好的指令碼函式。經過研究,發現了一些勉強的方法。 1. 用Response.Write方法寫入指令碼 比如在你單擊按鈕後,先操作資料庫,完了後顯示已經完成,可以在最後想呼叫的地

Tolua使用筆記二:luaC#的函式,變數互動方法

接著上一回的接著講: 案例三: 到這裡久終於到了大家最感興趣的地方了,熱更新的價值就在於用指令碼語言寫邏輯,這樣可以實現邏輯的頻繁改動而不用每次更新都重新下載。 而這個過程中必然涉及到C#對lua的一個邏輯呼叫,而這個例子實現的就是C#的函式的呼叫 核心程式碼如下:

Lua C/C++ 交系列:註冊枚舉enum到Lua Code中

mon size main 空間 log 方便 我們 .cpp lua 在Lua Code中註冊C/C++的枚舉很easy,就像註冊全局變量一樣。我們使用枚舉名稱作為命名空間,來避免註冊的枚舉發生沖突。註冊的枚舉存儲在全局環境(線程環境)中。 當在Lua Code中

C#在WinForm中使用WebKit傳遞js對象實現網頁交方法

復制代碼 dll ssa 所有 添加 spa load net clas 這篇文章主要介紹了C#在WinForm中使用WebKit傳遞js對象實現與網頁交互的方法,涉及針對WebBroswer控件及WebKit控件的相關使用技巧,需要的朋友可以參考下 本文實例講述了C#在W

luaC關鍵函數

const lua_next 素數 font con tab 成功 create 參數 1、lua_next(L, t_idx) 參數解釋: L:虛擬機 t_idx:table在棧中索引 返回 int:0執行失敗;非0執行成功

lua c/c++ 互動(6) lua呼叫C++(使用陣列 和字串函式

lua呼叫 c++ 的 兩個函式: 一個是 對lua 陣列 呼叫函式替換 陣列元素,一個 分割字串 test.lua --陣列操作 a = {1,2,3,4,5,6} swapArray(a,function(t) return t + 1 end) local

C++Lua進資料交換的工具函式

1)tolua.type 返回一個 C++ 物件的型別描述字串 格式: self.studio.layout = cc.CSLoader:createNode(GAMETABLE_CSB); print(tolua.type(self.studio.layout))    

Lua C/C++ 互動系列:通過C呼叫Lua函式(1)

1、Lua通過ANSI C 進行編寫,Lua與C互動要遵循一定的協議規則。在Lua 5.1 Reference Manual中明確規定如何通過C Code呼叫Lua 編寫的函式。      C  code可以呼叫Lua Code編寫的任何函式.本文主要以全域性函式來做演示

C/C++Lua之間進行資料函式互動以及解決“PANIC: unprotected error in call to Lua API (attempt t

在使用Cocos2d-x 時候,難免需要C/C++呼叫Lua函式、資料或Lua呼叫C/C++函式,那麼本篇講詳細介紹C/C++與Lua之間的資料、函式互動。 首先讓我們來簡單瞭解幾個Lua API函式: int   luaL_dofile (lua_Sta

C語言 在被調函式中改變指標變數值的方法

先看一段程式碼: #include <iostream>  void foo(char *p) {    p = "after foo()"; }      void main() {    char *p = "before foo()";    foo(

lua c++互動 之呼叫函式

</pre><pre name="code" class="cpp"> 對c/c++ 與lua的互動呼叫函式做一個小總結 #include <iostream>

C/C++ 常用的函式方法

1,建立多級目錄 #include <string> #include <direct.h> //_mkdir函式的標頭檔案 #include <io.h> //_access函式的標頭檔案 using name

C# 中物件Json轉的方法整理筆記

前言          原先一直做CS的開發,對Json瞭解不多,最近轉做BS後,才接觸到了Json。作為後臺與前端頁面資料互動的基礎,Json的地位非常重要,自然而然Json轉換方法的重要性也不言面喻。 最開始使用的是同事原來寫好的物件轉Json的方法,並沒有什麼問題,