Basic types
Tolua自動(dòng)將C/C++的基本類型映射到lua的基本類型。因此,char, int, float, 和 double映射到Lua的number類型;char *映射到string;void *映射到userdata。Types may be preceded by modifiers (unsigned, static, short, const, etc.);然而,認(rèn)識(shí)到tolua忽略了用于修飾基本類型的const(be aware that tolua ignores the modifier const if applied to basic types)。因此,如果我們傳遞一個(gè)基本類型的常數(shù)(conston)給Lua而后Lua再把該數(shù)返回給C/C++,這時(shí)非常量到常量之間的轉(zhuǎn)換會(huì)在后臺(tái)悄悄的進(jìn)行。
C/C++的函數(shù)也可以明確的使用Lua的對象。因此lua_Object也被認(rèn)為是一個(gè)基本類型。所以,任何的Lua都滿足這一要求。
新的tolua + + :在C++中的string類型同樣被認(rèn)為是基本類型,會(huì)被當(dāng)作值創(chuàng)遞給lua(使用c_str()方法)。這個(gè)功能可以使用命令行-S進(jìn)行關(guān)閉。
User defined types
所有在package文件里的其他類型都會(huì)被認(rèn)為是用戶自定義類型。它們會(huì)映射到Lua的userdata類型。Lua只能存儲(chǔ)指向用戶定義類型的指針;但是,tolua會(huì)自動(dòng)產(chǎn)生必要的安排來處理引用和值。例如,如果一個(gè)函數(shù)或方法返回一個(gè)用戶定義類型的值,當(dāng)這個(gè)值返回lua的時(shí)候,tolua會(huì)分配一個(gè)克隆對象,同時(shí)會(huì)設(shè)置垃圾收集標(biāo)記,用于在Lua不再使用該對象時(shí)自動(dòng)釋放。
對于用戶定義類型,常量是被保留的。因此將非常量用戶定義類型數(shù)據(jù)作為常量參數(shù)傳遞給一個(gè)函數(shù),會(huì)產(chǎn)生類型不匹配的錯(cuò)誤。
NULL and nil
C/C++ 的NULL或0指針映射到Lua的nil類型;反之,nil可能會(huì)指向任何可能的C/C++指針(conversely, nil may be specified wherever a C/C++ pointer is expected.)。
Typedefs
Tolua還接受package文件簡單的typedef(tolua also accepts simple typedef's inside the package files.)。任何一種類型當(dāng)定義的時(shí)候,tolua會(huì)將其映射到基本類型。它們是很有用的因?yàn)橐恍﹑ackage會(huì)將C/C++類型重新定制轉(zhuǎn)為它們的類型。例如,一個(gè)package可以定義類型real來表示一個(gè)double類型。在這種情況下,real可用于被lua解析的指定類型變量的package文件(real can be used to specify the variable types inside the package file interpreted by tolua),但只有我們在使用之前包括下面的定義:
typedef double real;
否則,real將會(huì)被解釋為用戶定義類型而不會(huì)映射到Lua的number類型。
Including real header files
在package文件中,我們必須指定對應(yīng)的頭文件,這些頭文件包含著我們要訪問的常數(shù),變量,函數(shù)和類。在package文件里任意以$ (except $[hclp]file, $[ , and $] lines)開頭的一行會(huì)被無修過的插入到生成的綁定到C/C++的代碼,但是會(huì)消除$號(hào)本身。我們用這個(gè)特性類引入真正的頭文件。所以,我們的頭文件一般會(huì)設(shè)置$作為開始,指定對應(yīng)要引用的文件,那些package需要的文件。
/* specify the files to be included */
$#include "header1.h" // include first header
$#include "header2.h" // include second header
As illustrated, tolua also accepts comments, using C or C++ convention, inside the package file. Nested C-like comments can also be used.
還注意到,文件中的$cfile或$hfile不需要使用該方式,這個(gè)tolua自動(dòng)完成。
在下面的章節(jié),我們將介紹如何指定我們想要綁定到lua的C/C++代碼。這些格式簡單并且符合C/C++的聲明方式。
Binding constants
Tolua支持兩種用于綁定常數(shù)的方式:define's和enum's。對于define's的一般格式是:
#define NAME [ VALUE ]
上面的VALUE是可以選擇的(The value, as showed above, is optional)。如果這樣的代碼出現(xiàn)在要被解析的文件中,tolua會(huì)將NAME作為Lua的全局變量,該全局變量是C/C++的常量,值為VALUE。只接受數(shù)字常量。
新的tolua++:所有其他預(yù)處理指令會(huì)被忽略。
對于enum's的一般格式是:
enum {
NAME1 [ = VALUE1 ] ,
NAME2 [ = VALUE2 ] ,
...
NAMEn [ = VALUEn ]
};
同樣的,tolua創(chuàng)建一系列全局變量,命名為NAMEi,對應(yīng)values。
Binding external variables
全局外部變量同樣可以暴露出來。在已清理的頭文件(cleaned header file),他們都指定為:
[extern] type var;
Tolua將這種聲明綁定到Lua的全局變量中。因此,在Lua里,我們可以很自然的訪問C/C++變量。如果變量不是常數(shù),我們還可以在Lua賦予該變量新的值。全局?jǐn)?shù)組同樣可以被綁定到Lua里。數(shù)組可以是任意類型。數(shù)組對應(yīng)的Lua類型是table,對應(yīng)以數(shù)字作為下標(biāo)(indexed with numeric values);但是,要注意的是Lua中下標(biāo)1對應(yīng)C/C++中的下標(biāo)0。數(shù)組一定要定長(be pre dimensioned)。例如
double v[10];
新的tolua++:外部變量可以使用tolua_readonly修飾。(see Additional Features)
Binding functions
函數(shù)也指定為傳統(tǒng)的C/C++聲明:
type funcname (type1 par1[, type2 par2[,...typeN parN]]);
返回類型可以是void,表示沒有返回值。函數(shù)也可以沒有參數(shù)。在這種情況下,void可能被指定到函數(shù)的參數(shù)列表里(specified in the place of the list of parameters.)。參數(shù)類型必須遵循發(fā)布(posted)的規(guī)則。Tolua創(chuàng)建一個(gè)Lua函數(shù)綁定C/C++函數(shù)。當(dāng)Lua調(diào)用函數(shù)時(shí),參數(shù)類型必須對應(yīng)C/C++的類型,否則tolua會(huì)產(chǎn)生一個(gè)錯(cuò)誤并報(bào)告錯(cuò)誤參數(shù)。如果參數(shù)名是省略的,tolua會(huì)自定命名,但是類型必須是基本類型或者是以前使用過的用戶定義類型。
Arrays
Tolua同時(shí)支持以數(shù)組作為參數(shù)的函數(shù)或方法。最每秒的事情是,當(dāng)數(shù)組映射到lua的table后,當(dāng)C/C++函數(shù)改變了數(shù)組里面的值,會(huì)實(shí)時(shí)更新到lua的table中。
數(shù)組的大小必須是事先定義好多。例如:
void func (double a[3]);
在tolua里這是一個(gè)合法的函數(shù)聲明,在lua里調(diào)用這個(gè)函數(shù)方法如:
p = {1.0,1.5,8.6}
func (p)
數(shù)組長度不一定是一個(gè)常數(shù)表達(dá)式;還可以是在運(yùn)行過程中能計(jì)算出結(jié)果的表達(dá)式。例如:
void func (int n, int m, double image[n*m]);
這個(gè)是合法的。因?yàn)楸磉_(dá)式n*m在函數(shù)的綁定范圍(expression n*m is valid in the binding function scope)。但是必須考慮到,tolua使用動(dòng)態(tài)分配的方式綁定函數(shù),這一方式會(huì)降低性能。
盡管尺寸匹配是必須的,但是更重要的是意識(shí)到,所有數(shù)組傳遞給實(shí)際C/C++函數(shù)是,是使用局部變量的方式進(jìn)行傳遞。因此,如果C/C++函數(shù)想要保留這個(gè)數(shù)組供以后使用,這段代碼可能不會(huì)如想象那樣工作。
Overloaded functions
Tolua還支持重載函數(shù)。區(qū)分兩個(gè)同名函數(shù)的方法是基于映射到lua的參數(shù)類型。因此
void func (int a);
void func (double a);
在C/C++中這代表兩個(gè)不同的函數(shù),然而在tolua里它們是同一個(gè)函數(shù),因?yàn)閕nt和double類型都映射到number。
另一個(gè)棘手的情況時(shí),當(dāng)遇到指針時(shí)。假設(shè):
void func (char* s);
void func (void* p);
void func (Object1* ptr);
void func (Object2* prt);
盡管在C++中這是4個(gè)不同的函數(shù),但是映射到Lua里面的聲明:
func(nil)
重要的是,運(yùn)行的時(shí)候tolua決定那個(gè)函數(shù)被調(diào)用,嘗試映射到那些提供的函數(shù)。Tolua第一次嘗試調(diào)用最后一個(gè)指定的函數(shù);如果失敗,tolua接著嘗試前一個(gè)函數(shù)。這個(gè)過程一直持續(xù)到找到一個(gè)能成功運(yùn)行的代碼或者到第一個(gè)函數(shù)。因?yàn)檫@個(gè)原因,不匹配的錯(cuò)誤信息的發(fā)出,總是基于第一個(gè)函數(shù)的規(guī)格(the mismatching error message, when it occurs, is based on the first function specification)。當(dāng)性能很重要時(shí),我們應(yīng)該把最常用的函數(shù)放在最后一個(gè)。
Tolua支持C的重載函數(shù)。(see Renaming for details.)
Default parameter values
最后的函數(shù)參數(shù)可以帶有默認(rèn)值。因此,如果函數(shù)調(diào)用時(shí)提供的參數(shù)不足,默認(rèn)值會(huì)自動(dòng)使用。該格式指定的默認(rèn)值與C++里面的是一致的。
type funcname (..., typeN-1 parN-1 [= valueN-1], typeN parN [= valueN]);
toLua執(zhí)行此功能無需使用任何C++的機(jī)制;因此,同樣支持綁定C的函數(shù)。
我們同樣可以指定數(shù)組的默認(rèn)值(沒有辦法指定一個(gè)默認(rèn)值為數(shù)組本身)。例如:
void func (int a[5]=0);
把數(shù)組的所有值設(shè)為0.因此,這個(gè)函數(shù)可以直接在lua調(diào)用無需初始化table。
對于lua對象類型(lua_Object),tolua定義了一個(gè)常量用來指定nil為默認(rèn)值:
void func (lua_Object lo = TOLUA_NIL);
新的tolua++ :C++類的構(gòu)造是有效的默認(rèn)參數(shù)。例如:
void set_color(const Color& color = Color(0,0,0));
Multiple returned values
在lua中函數(shù)可以返回任意個(gè)數(shù)的值。Tolua使用這個(gè)特性來模擬值傳遞。如果一個(gè)函數(shù)的參數(shù)指定為一個(gè)指針或引用的一個(gè)基本類型或一個(gè)指針或引用的一個(gè)指針一個(gè)用戶定義的類型,tolua接受對應(yīng)類型的傳入和返回,除了常規(guī)的函數(shù)返回,還可以通過參數(shù)更新的形式。
例如,考慮用于交換數(shù)值的C函數(shù):
void swap (double* x, double* y);
or
void swap (double& x, double& y);
如果這函數(shù)在package文件中聲明,tolue綁定該函數(shù)為輸入兩個(gè)參數(shù),返回兩個(gè)值。所以,正確的Lua代碼為:
x,y = swap(x,y)
如果輸入值不使用,lua會(huì)自動(dòng)使用默認(rèn)參數(shù)值調(diào)用函數(shù)而不需要指定它們。
void getBox (double* xmin=0, double* xmax=0, double* ymin=0, double* ymax=0);
In Lua:
xmin, xmax, ymin, ymax = getBox()
如果是用戶定義類型,則以下面為例:
void update (Point** p);
or
void update (Point*& p);
Binding struct fields
用戶定義類型可以很好的被tolua綁定。對于每一個(gè)變量或函數(shù)類型,不符合基本類型, tolua自動(dòng)創(chuàng)建一個(gè)標(biāo)簽的用戶數(shù)據(jù)代表的C/C++類型。
如果類型對應(yīng)結(jié)構(gòu),Lua可以通過下標(biāo)直接訪問結(jié)構(gòu)里面的內(nèi)容,indexing a variable that holds an object of such a type. 在C代碼,這些類型通常是用typedef定義的:
typedef struct [name] {
type1 fieldname1;
type2 fieldname2;
...
typeN fieldnameN;
} typename;
如果這段代碼正在被插入到package文件中,tolua允許任何擁有類型對象名的對象反問任何索引列出的變量的字段名字(If such a code is inserted in the package file being processed, tolua allows any variable that holds an object of type typename to access any listed field indexing the variable by the field name.)。例如,如果var持有對象, var.fieldnamei可以訪問fieldnamei里面的東西。
塊內(nèi)的數(shù)組同樣被映射。
typedef struct {
int x[10];
int y[10];
} Example;
Binding classes and methods
Tolua支持C++的類定義。事實(shí)上,tolua能很自然的處理單一繼承和多態(tài)性。以下各小節(jié)將會(huì)介紹什么可以暴露給lua,在類定義的時(shí)候(The subsections below describe what can be exported by a class definition.)。