翻譯自http://gamedevgeek.com/tutorials/calling-c-functions-from-lua/
在Lua中調用C++函數
我的第二部分教程講解了怎樣在C++中調用Lua函數。在這部分中,我們將討論相反的情況——在Lua中調用C++函數。由於我沒有想到一個簡單的例子來說明這種情況,因此,我借用了Lua官方文檔中的average函數來進行講解。
本教程涵蓋了Lua5.1。在Lua的每一個版本中都有一些非常不同之處。下面的範例程式碼將不能在老版本的Lua下運行。如果你仍然在使用老版本而且不願意升級,不用擔心,我已經在文章底部提供了4.0和5.0教程的原始碼下載串連。好了,讓我們開始吧!
在本文中我們將用C++建立一個函數,告訴Lua解譯器它的情況,最後從Lua中調用它並使用其結果。我在後面也將談一談Lua程式中的錯誤檢查。
定義函數
第一步是定義函數。所有在Lua中被調用的C/C++函數將使用下面一類指標進行調用:
typedef int (*lua_CFunction) (lua_State *L);
換句話說,函數必須要以Lua解譯器作為唯一的參數,並且返回一個唯一的整數。由於用一個Lua解譯器作為參數,因此函數實際上能夠從棧中取得任意數量的參數。在後面我們將看到,返回的整數實際上是被壓入棧的值的個數。通過如此容易的封裝,就能滿足你在Lua中調用C++函數的需求。
下面給出的C++函數average()示範了如何接受多個參數且返回超過一個值。記住,該函數是一個與上面typedef相匹配的函數。
- lua_gettop函數返回棧頂的索引值。因為在Lua中棧是從1開始編號的,因此該函數獲得的值就是參數的個數。
- 在for迴圈中計算所有參數之和。
- 調用lua_pushnumber()將參數的平均值壓棧。
- 將參數之和壓入棧中。
- 最後,函數返回2,說明有兩個傳回值在棧中。
現在C++函數已經被定義好了,我們必須將它告訴Lua解譯器。這將在main函數中初始化Lua解譯器和載入庫完成之後完成:
/* 註冊函數 */
lua_register(L, "average", average);
儲存檔案為luaavg.cpp。如果你直接使用C而不是C++,將檔案名稱改為luaavg.c,然後將extern "C"刪除。
#include <stdio.h>
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
/* 指向Lua解譯器的指標 */
lua_State* L;
static int average(lua_State *L)
{ /* 得到參數個數 */
int n = lua_gettop(L);
double sum = 0;
int i;
/* 迴圈求參數之和 */
for (i = 1; i <= n; i++)
{
/* 求和 */
sum += lua_tonumber(L, i);
}
/* 壓入平均值 */
lua_pushnumber(L, sum / n);
/* 壓入和 */
lua_pushnumber(L, sum);
/* 返回傳回值的個數 */
return 2;
}
int main ( int argc, char *argv[] )
{
/* 初始化Lua */
L = lua_open();
/* 載入Lua基本庫 */
luaL_openlibs(L);
/* 註冊函數 */
lua_register(L, "average", average);
/* 運行指令碼 */
luaL_dofile(L, "avg.lua");
/* 清除Lua */
lua_close(L);
/* 暫停 */
printf( "Press enter to exit…" );
getchar();
return 0;
}
下面是以5個參數調用average函數並且顯示兩個傳回值的Lua指令碼,我們將其儲存為avg.lua:
-- call a C++ function
avg, sum = average(10, 20, 30, 40, 50)
print("The average is ", avg)
print("The sum is ", sum)
編譯
在Linux下,在命令列鍵入:
g++ luaavg.cpp -llua -llualib -o luaavg
然後,鍵入下列命令運行:
./luaavg
如果沒有問題, 程式將顯示出平均值、和。
在Visual C++你將需要進行下列步驟:
- 建立一個新的空Win32控制台應用工程。
- 將"luatest.cpp"加入你的工程。
- 選擇項目菜單中的屬性菜單。
- 在"連接器"的"輸入"欄目的"附加依賴項"中輸入"lua5.1.lib"。
- 確定。
此時,按F7構建程式。
如果你採用的是dll庫,請確保將其放在應用程式的目錄中或者windows系統能夠找到它的地方。如果你採用的是靜態串連庫,則不需要。
錯誤處理
如果你已經閱讀了Lua的API文檔,你將看出實際上我上面的average函數沒有進行錯誤檢查。這樣做是為了更容易地講解,然而在真實的程式中你應該做一些錯誤偵測。在上面的例子中,我們至少應該檢查每個參數是不是數字。通過在for迴圈中添加下面的代碼來實現:
if (!lua_isnumber(L, i)) {
lua_pushstring(L, "Incorrect argument to 'average'");
lua_error(L);
}
添加這樣的檢查很容易,同時這樣也讓調試更容易。當處理用兩種不同語言編寫的程式的時候,這顯得相當重要。
(本文由Groov0V翻譯,轉載請指明出處!)