去年我作了一個(gè)Lua腳本的C++包裝,有許多朋友感興趣,并嘗試使用,我感到受寵若驚。事實(shí)上,我作的包裝,學(xué)習(xí)的目的比較強(qiáng),它還是有許多缺陷的。為了讓朋友們少走彎路,我推薦使用LuaPlus作為C++的包裝。
LuaPlus是Lua的C++增強(qiáng),也就是說(shuō),LuaPlus本身就是在Lua的源碼上進(jìn)行增強(qiáng)得來(lái)的。用它與C++進(jìn)行合作,是比較好的一個(gè)選擇。
LuaPlus目前版本為:LuaPlus for Lua 5.01 Distribution Build 1080 (February 28, 2004)。大家可以到http://luaplus.org/ 站點(diǎn)下載:
源碼 (http://wwhiz.com/LuaPlus/LuaPlus50_Build1081.zip)
目標(biāo)碼 (http://wwhiz.com/LuaPlus/LuaPlus50_Build1081_Win32Binaries.zip)
我將在下面說(shuō)明,如何使用LuaPlus,以及如何更方便的讓LuaPlus與C++的類合作無(wú)間。
1. 調(diào)用Lua腳本
// 創(chuàng)建Lua解釋器:
LuaStateOwner state;
// 執(zhí)行Lua腳本:
state->DoString("print('Hello World\n')");
// 載入Lua腳本文件并執(zhí)行:
state->DoFile("C:\\test.lua");
// 載入編譯后的Lua腳本文件并執(zhí)行:
state->DoFile("C:\\test.luac");
2. 與Lua腳本互相調(diào)用
// 為L(zhǎng)ua腳本設(shè)置變量
state->GetGlobals().SetNumber("myvalue", 123456);
// 獲得Lua變量的值
int myvalue = state->GetGlobal("myvalue").GetInteger();
// 調(diào)用Lua函數(shù)
LuaFunction<int> luaPrint = state->GetGlobal("print");
luaPrint("Hello World\n");
// 讓Lua調(diào)用C語(yǔ)言函數(shù)
int add(int a, int b){ return a+b;}
state->GetGlobals().RegisterDirect("add", add);
state->DoString("print(add(3,4))");
// 讓Lua調(diào)用C++類成員函數(shù)
class Test{public: int add(int a, int b){return a+b;}};
Test test;
state->GetGlobals().RegisterDirect("add", test, add);
state->DoString("print(add(3,4))");
3. 在Lua腳本中使用C++類
這個(gè)稍微有點(diǎn)小麻煩。不過(guò),我包裝了一個(gè)LuaPlusHelper.h的文件,它可以很輕松的完成這個(gè)工作。它的實(shí)現(xiàn)也很簡(jiǎn)單,大家可以從源碼上來(lái)獲得如何用純LuaPlus實(shí)現(xiàn)同樣的功能。
不過(guò),這里仍然有一個(gè)限制沒(méi)有解決:不能使用虛成員函數(shù)。不過(guò)考慮到我們僅是在Lua調(diào)用一下C++函數(shù),并不是要將C++完美的導(dǎo)入到Lua,這個(gè)限制完全可以接受。
另外,類成員變量不能直接在Lua中訪問(wèn),可以通過(guò)類成員函數(shù)來(lái)訪問(wèn)(比如SetValue/GetValue之類)。
// 下面是一個(gè)簡(jiǎn)單的C++類:
class Logger
{
public:
void LOGMEMBER(const char* message)
{
printf("In member function: %s\n", message);
}
Logger()
{
printf("Constructing(%p)...\n", this);
v = 10;
}
virtual ~Logger()
{
printf("Destructing(%p)...\n", this);
}
Logger(int n)
{
printf(" -- Constructing[%d](%p)...\n", n, this);
}
Logger(Logger* logger)
{
printf(" -- Constructing[%p](%p)...\n", logger, this);
logger->LOGMEMBER(" Call From Constructor\n");
}
int SetValue(int val)
{
v = val;
}
int GetValue()
{
return v;
}
public:
int v;
};
// 導(dǎo)入到Lua腳本:
LuaClass<Logger>(state)
.create("Logger") // 定義構(gòu)造函數(shù) Logger::Logger()
.create<int>("Logger2") // 定義構(gòu)造函數(shù) Logger::Logger(int)
.create<Logger*>("Logger3") // 定義構(gòu)造函數(shù) Logger::Logger(Logger*)
.destroy("Free") // 定義析構(gòu)函數(shù) Logger::~Logger()
.destroy("__gc") // 定義析構(gòu)函數(shù) Logger::~Logger()
.def("lm", &Logger::LOGMEMBER) // 定義成員函數(shù) Logger::LOGMEMBER(const char*)
.def("SetValue", &Logger::SetValue)
.def("GetValue", &Logger::GetValue);
// 在Lua中使用Logger類(1):
state->DoString(
"l = Logger();" // 調(diào)用構(gòu)造函數(shù) Logger::Logger()
"l.lm('Hello World 1');" // 調(diào)用成員函數(shù) Logger::LOGMEMBER(const char*)
"l.Free();" // 調(diào)用析構(gòu)函數(shù) Logger::~Logger()
);
// 在Lua中使用Logger類(2):
state->DoString(
"m = Logger(10);" // 調(diào)用構(gòu)造函數(shù) Logger::Logger(int)
"m.lm('Hello World 2');" // 調(diào)用成員函數(shù) Logger::LOGMEMBER(const char*)
"n = Logger(m);" // 調(diào)用構(gòu)造函數(shù) Logger::Logger(Logger*)
"n.lm('Hello World 3');" // 調(diào)用成員函數(shù) Logger::LOGMEMBER(const char*)
"m.SetValue(11);"
"print(m.GetValue());"
"m,n = nil, nil;" // m,n 將由Lua的垃極回收來(lái)調(diào)用析構(gòu)函數(shù)
);
4. 將一組C函數(shù)歸類到Lua模塊
//同上面一樣,我采用LuaPlusHelper.h來(lái)簡(jiǎn)化:
LuaModule(state, "mymodule")
.def("add", add)
.def("add2", test, add);
state->DoString(
"print(mymodule.add(3,4));"
"print(mymodule.add2(3,4));"
);
5. 使用Lua的Table數(shù)據(jù)類型
// 在Lua中創(chuàng)建Table
LuaObject table = state->GetGlobals().CreateTable("mytable");
table.SetInteger("m", 10);
table.SetNumber("f", 1.99);
table.SetString("s", "Hello World");
table.SetWString("ch", L"你好");
table.SetString(1, "What");
// 相當(dāng)于Lua中的:
// mytable = {m=10, f=1.99, s="Hello World", ch=L"你好", "What"}
// 也可以使用table作為key和value:
state->GetGlobals().CreateTable("nexttable")
.SetString(table, "Hello")
.SetObject("obj", table);
// 相當(dāng)于Lua中的:
// nexttable = {mytable="Hello", obj=mytable}
//獲得Table的內(nèi)容:
LuaObject t2 = state->GetGlobals("mytable");
int m = t2.GetByName("m").GetInteger();
LuaObject t3 = state->GetGlobals("nexttable");
std::string str = t3.GetByObject(t2).GetString();
6 遍歷Table
LuaStateOwner state;
state.DoString( "MyTable = { Hi = 5, Hello = 10, Yo = 6 }" );
LuaObject obj = state.GetGlobals()[ "MyTable" ];
for ( LuaTableIterator it( obj ); it; it.Next() )
{
const char* key = it.GetKey().GetString();
int num = it.GetValue().GetInteger();
}
篇尾
上面我只是簡(jiǎn)單的舉一些例子來(lái)說(shuō)明LuaPlus以及LuaPlusHelper的使用方法,具體文檔請(qǐng)參見(jiàn)LuaPlus。
需要下載LuaPlusHelper,請(qǐng)點(diǎn)這里:
http://www.d2-life.com/LBS/attachments/month_200509/06_zwo3LuaPlusHelper.zip
作者: 沐楓 (第二人生成員)
版權(quán)所有轉(zhuǎn)載請(qǐng)注明原出處
主頁(yè):第二人生
http://www.d2-life.com http://www.d2-life.com/LBS/blogview.asp?logID=39 在這篇文章中,我想向大家介紹如何進(jìn)行Lua程序設(shè)計(jì)。我假設(shè)大家都學(xué)過(guò)至少一門編程語(yǔ)言,比如Basic或C,特別是C。因?yàn)長(zhǎng)ua的最大用途是在宿主程序中作為腳本使用的。
Lua 的語(yǔ)法比較簡(jiǎn)單,學(xué)習(xí)起來(lái)也比較省力,但功能卻并不弱。
在Lua中,一切都是變量,除了關(guān)鍵字。請(qǐng)記住這句話。
I. 首先是注釋
寫一個(gè)程序,總是少不了注釋的。
在Lua中,你可以使用單行注釋和多行注釋。
單行注釋中,連續(xù)兩個(gè)減號(hào)"--"表示注釋的開(kāi)始,一直延續(xù)到行末為止。相當(dāng)于C++語(yǔ)言中的"http://"。
多行注釋中,由"--[["表示注釋開(kāi)始,并且一直延續(xù)到"]]"為止。這種注釋相當(dāng)于C語(yǔ)言中的"/*…*/"。在注釋當(dāng)中,"[["和"]]"是可以嵌套的。
II. Lua編程
經(jīng)典的"Hello world"的程序總是被用來(lái)開(kāi)始介紹一種語(yǔ)言。在Lua中,寫一個(gè)這樣的程序很簡(jiǎn)單:
print("Hello world")
在Lua中,語(yǔ)句之間可以用分號(hào)";"隔開(kāi),也可以用空白隔開(kāi)。一般來(lái)說(shuō),如果多個(gè)語(yǔ)句寫在同一行的話,建議總是用分號(hào)隔開(kāi)。
Lua 有好幾種程序控制語(yǔ)句,如:
條件控制:if 條件 then … elseif 條件 then … else … end
While循環(huán):while 條件 do … end
Repeat循環(huán):repeat … until 條件
For循環(huán):for 變量 = 初值,終點(diǎn)值,步進(jìn) do … end
For循環(huán):for 變量1,變量2,… ,變量N in表或枚舉函數(shù) do … end
注意一下,for的循環(huán)變量總是只作用于for的局部變量,你也可以省略步進(jìn)值,這時(shí)候,for循環(huán)會(huì)使用1作為步進(jìn)值。
你可以用break來(lái)中止一個(gè)循環(huán)。
如果你有程序設(shè)計(jì)的基礎(chǔ),比如你學(xué)過(guò)Basic,C之類的,你會(huì)覺(jué)得Lua也不難。但Lua有幾個(gè)地方是明顯不同于這些程序設(shè)計(jì)語(yǔ)言的,所以請(qǐng)?zhí)貏e注意。
.語(yǔ)句塊
語(yǔ)句塊在C++中是用"{"和"}"括起來(lái)的,在Lua中,它是用do 和 end 括起來(lái)的。比如:
do print("Hello") end
你可以在 函數(shù) 中和 語(yǔ)句塊 中定局部變量。
.賦值語(yǔ)句
賦值語(yǔ)句在Lua被強(qiáng)化了。它可以同時(shí)給多個(gè)變量賦值。
例如:
a,b,c,d=1,2,3,4
甚至是:
a,b=b,a -- 多么方便的交換變量功能啊。
在默認(rèn)情況下,變量總是認(rèn)為是全局的。假如你要定義局部變量,則在第一次賦值的時(shí)候,需要用local說(shuō)明。比如:
local a,b,c = 1,2,3 -- a,b,c都是局部變量
.?dāng)?shù)值運(yùn)算
和C語(yǔ)言一樣,支持 +, -, *, /。但Lua還多了一個(gè)"^"。這表示指數(shù)乘方運(yùn)算。比如2^3 結(jié)果為8, 2^4結(jié)果為16。
連接兩個(gè)字符串,可以用".."運(yùn)處符。如:
"This a " .. "string." -- 等于 "this a string"
.比較運(yùn)算
< > <= >= == ~=
分別表示 小于,大于,不大于,不小于,相等,不相等
所有這些操作符總是返回true或false。
對(duì)于Table,F(xiàn)unction和Userdata類型的數(shù)據(jù),只有 == 和 ~=可以用。相等表示兩個(gè)變量引用的是同一個(gè)數(shù)據(jù)。比如:
a={1,2}
b=a
print(a==b, a~=b) -- true, false
a={1,2}
b={1,2}
print(a==b, a~=b) -- false, true
.邏輯運(yùn)算
and, or, not
其中,and 和 or 與C語(yǔ)言區(qū)別特別大。
在這里,請(qǐng)先記住,在Lua中,只有false和nil才計(jì)算為false,其它任何數(shù)據(jù)都計(jì)算為true,0也是true!
and 和 or的運(yùn)算結(jié)果不是true和false,而是和它的兩個(gè)操作數(shù)相關(guān)。
a and b:如果a為false,則返回a;否則返回b
a or b:如果 a 為true,則返回a;否則返回b
舉幾個(gè)例子:
print(4 and 5) --> 5
print(nil and 13) --> nil
print(false and 13) --> false
print(4 or 5) --> 4
print(false or 5) --> 5
在Lua中這是很有用的特性,也是比較令人混洧的特性。
我們可以模擬C語(yǔ)言中的語(yǔ)句:x = a? b : c,在Lua中,可以寫成:x = a and b or c。
最有用的語(yǔ)句是: x = x or v,它相當(dāng)于:if not x then x = v end 。
.運(yùn)算符優(yōu)先級(jí),從高到低順序如下:
^
not - (一元運(yùn)算)
* /
+ -
..(字符串連接)
< > <= >= ~= ==
and
or
III. 關(guān)鍵字
關(guān)鍵字是不能做為變量的。Lua的關(guān)鍵字不多,就以下幾個(gè):
and break do else elseif
end false for function if
in local nil not or
repeat return then true until while
IV. 變量類型
怎么確定一個(gè)變量是什么類型的呢?大家可以用type()函數(shù)來(lái)檢查。Lua支持的類型有以下幾種:
Nil 空值,所有沒(méi)有使用過(guò)的變量,都是nil。nil既是值,又是類型。
Boolean 布爾值
Number 數(shù)值,在Lua里,數(shù)值相當(dāng)于C語(yǔ)言的double
String 字符串,如果你愿意的話,字符串是可以包含'\0'字符的
Table 關(guān)系表類型,這個(gè)類型功能比較強(qiáng)大,我們?cè)诤竺媛f(shuō)。
Function 函數(shù)類型,不要懷疑,函數(shù)也是一種類型,也就是說(shuō),所有的函數(shù),它本身就是一個(gè)變量。
Userdata 嗯,這個(gè)類型專門用來(lái)和Lua的宿主打交道的。宿主通常是用C和C++來(lái)編寫的,在這種情況下,Userdata可以是宿主的任意數(shù)據(jù)類型,常用的有Struct和指針。
Thread 線程類型,在Lua中沒(méi)有真正的線程。Lua中可以將一個(gè)函數(shù)分成幾部份運(yùn)行。如果感興趣的話,可以去看看Lua的文檔。
V. 變量的定義
所有的語(yǔ)言,都要用到變量。在Lua中,不管你在什么地方使用變量,都不需要聲明,并且所有的這些變量總是全局變量,除非,你在前面加上"local"。
這一點(diǎn)要特別注意,因?yàn)槟憧赡芟朐诤瘮?shù)里使用局部變量,卻忘了用local來(lái)說(shuō)明。
至于變量名字,它是大小寫相關(guān)的。也就是說(shuō),A和a是兩個(gè)不同的變量。
定義一個(gè)變量的方法就是賦值。"="操作就是用來(lái)賦值的
我們一起來(lái)定義幾種常用類型的變量吧。
A. Nil
正如前面所說(shuō)的,沒(méi)有使用過(guò)的變量的值,都是Nil。有時(shí)候我們也需要將一個(gè)變量清除,這時(shí)候,我們可以直接給變量賦以nil值。如:
var1=nil -- 請(qǐng)注意 nil 一定要小寫
B. Boolean
布爾值通常是用在進(jìn)行條件判斷的時(shí)候。布爾值有兩種:true 和 false。在Lua中,只有false和nil才被計(jì)算為false,而所有任何其它類型的值,都是true。比如0,空串等等,都是true。不要被C語(yǔ)言的習(xí)慣所誤導(dǎo),0在Lua中的的確確是true。你也可以直接給一個(gè)變量賦以Boolean類型的值,如:
varboolean = true
C. Number
在Lua中,是沒(méi)有整數(shù)類型的,也不需要。一般情況下,只要數(shù)值不是很大(比如不超過(guò)100,000,000,000,000),是不會(huì)產(chǎn)生舍入誤差的。在很多CPU上,實(shí)數(shù)的運(yùn)算并不比整數(shù)慢。
實(shí)數(shù)的表示方法,同C語(yǔ)言類似,如:
4 0.4 4.57e-3 0.3e12 5e+20
D. String
字符串,總是一種非常常用的高級(jí)類型。在Lua中,你可以非常方便的定義很長(zhǎng)很長(zhǎng)的字符串。
字符串在Lua中有幾種方法來(lái)表示,最通用的方法,是用雙引號(hào)或單引號(hào)來(lái)括起一個(gè)字符串的,如:
"This is a string."
和C語(yǔ)言相同的,它支持一些轉(zhuǎn)義字符,列表如下:
\a bell
\b back space
\f form feed
\n newline
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\" double quote
\' single quote
\[ left square bracket
\] right square bracket
由于這種字符串只能寫在一行中,因此,不可避免的要用到轉(zhuǎn)義字符。加入了轉(zhuǎn)義字符的串,看起來(lái)實(shí)在是不敢恭維,比如:
"one line\nnext line\n\"in quotes\", 'in quotes'"
一大堆的"\"符號(hào)讓人看起來(lái)很倒胃口。如果你與我有同感,那么,我們?cè)贚ua中,可以用另一種表示方法:用"[["和"]]"將多行的字符串括起來(lái),如:
page = [[
<HTML>
<HEAD>
<TITLE>An HTML Page</TITLE>
</HEAD>
<BODY>
<A HREF="
lua' target=_blank>
http://www.lua.org">Lua</A> [[a text between double brackets]]
</BODY>
</HTML>
]]
值得注意的是,在這種字符串中,如果含有單獨(dú)使用的"[["或"]]"就仍然得用"\["或"\]"來(lái)避免歧義。當(dāng)然,這種情況是極少會(huì)發(fā)生的。
E. Table
關(guān)系表類型,這是一個(gè)很強(qiáng)大的類型。我們可以把這個(gè)類型看作是一個(gè)數(shù)組。只是C語(yǔ)言的數(shù)組,只能用正整數(shù)來(lái)作索引;在Lua中,你可以用任意類型來(lái)作數(shù)組的索引,除了nil。同樣,在C語(yǔ)言中,數(shù)組的內(nèi)容只允許一種類型;在Lua中,你也可以用任意類型的值來(lái)作數(shù)組的內(nèi)容,除了nil。
Table的定義很簡(jiǎn)單,它的主要特征是用"{"和"}"來(lái)括起一系列數(shù)據(jù)元素的。比如:
T1 = {} -- 定義一個(gè)空表
T1[1]=10 -- 然后我們就可以象C語(yǔ)言一樣來(lái)使用它了。
T1["John"]={Age=27, Gender="Male"}
這一句相當(dāng)于:
T1["John"]={} -- 必須先定義成一個(gè)表,還記得未定義的變量是nil類型嗎
T1["John"]["Age"]=27
T1["John"]["Gender"]="Male"
當(dāng)表的索引是字符串的時(shí)候,我們可以簡(jiǎn)寫成:
T1.John={}
T1.John.Age=27
T1.John.Gender="Male"
或
T1.John{Age=27, Gender="Male"}
這是一個(gè)很強(qiáng)的特性。
在定義表的時(shí)候,我們可以把所有的數(shù)據(jù)內(nèi)容一起寫在"{"和"}"之間,這樣子是非常方便,而且很好看。比如,前面的T1的定義,我們可以這么寫:
T1=
{
10, -- 相當(dāng)于 [1] = 10
[100] = 40,
John= -- 如果你原意,你還可以寫成:["John"] =
{
Age=27, -- 如果你原意,你還可以寫成:["Age"] =27
Gender=Male -- 如果你原意,你還可以寫成:["Gender"] =Male
},
20 -- 相當(dāng)于 [2] = 20
}
看起來(lái)很漂亮,不是嗎?我們?cè)趯懙臅r(shí)候,需要注意三點(diǎn):
第一,所有元素之間,總是用逗號(hào)","隔開(kāi);
第二,所有索引值都需要用"["和"]"括起來(lái);如果是字符串,還可以去掉引號(hào)和中括號(hào);
第三,如果不寫索引,則索引就會(huì)被認(rèn)為是數(shù)字,并按順序自動(dòng)從1往后編;
表類型的構(gòu)造是如此的方便,以致于常常被人用來(lái)代替配置文件。是的,不用懷疑,它比ini文件要漂亮,并且強(qiáng)大的多。
F. Function
函數(shù),在Lua中,函數(shù)的定義也很簡(jiǎn)單。典型的定義如下:
function add(a,b) -- add 是函數(shù)名字,a和b是參數(shù)名字
return a+b -- return 用來(lái)返回函數(shù)的運(yùn)行結(jié)果
end
請(qǐng)注意,return語(yǔ)言一定要寫在end之前。假如你非要在中間放上一句return,那么請(qǐng)寫成:do return end。
還記得前面說(shuō)過(guò),函數(shù)也是變量類型嗎?上面的函數(shù)定義,其實(shí)相當(dāng)于:
add = function (a,b) return a+b end
當(dāng)你重新給add賦值時(shí),它就不再表示這個(gè)函數(shù)了。你甚至可以賦給add任意數(shù)據(jù),包括nil (這樣,你就清除了add變量)。Function是不是很象C語(yǔ)言的函數(shù)指針呢?
和C語(yǔ)言一樣,Lua的函數(shù)可以接受可變參數(shù)個(gè)數(shù),它同樣是用"…"來(lái)定義的,比如:
function sum (a,b,…)
如果想取得…所代表的參數(shù),可以在函數(shù)中訪問(wèn)arg局部變量(表類型)得到。
如 sum(1,2,3,4)
則,在函數(shù)中,a = 1, b = 2, arg = {3, 4}
更可貴的是,它可以同時(shí)返回多個(gè)結(jié)果,比如:
function s()
return 1,2,3,4
end
a,b,c,d = s() -- 此時(shí),a = 1, b = 2, c = 3, d = 4
前面說(shuō)過(guò),表類型可以擁有任意類型的值,包括函數(shù)!因此,有一個(gè)很強(qiáng)大的特性是,擁有函數(shù)的表,哦,我想更恰當(dāng)?shù)膽?yīng)該說(shuō)是對(duì)象吧。Lua可以使用面向?qū)ο缶幊塘恕2恍牛磕俏遗e例如下:
t =
{
Age = 27
add = function(self, n) self.Age = self.Age+n end
}
print(t.Age) -- 27
t.add(t, 10)
print(t.Age) -- 37
不過(guò),t.add(t,10) 這一句實(shí)在是有點(diǎn)土對(duì)吧?沒(méi)關(guān)系,在Lua中,你可以簡(jiǎn)寫成:
t:add(10) -- 相當(dāng)于 t.add(t,10)
G. Userdata 和 Thread
這兩個(gè)類型的話題,超出了本文的內(nèi)容,就不打算細(xì)說(shuō)了。
VI. 結(jié)束語(yǔ)
就這么結(jié)束了嗎?當(dāng)然不是,接下來(lái),需要用Lua解釋器,來(lái)幫助你理解和實(shí)踐了。這篇小文只是幫助你大體了解Lua的語(yǔ)法。如果你有編程基礎(chǔ),相信會(huì)很快對(duì)Lua上手了。
就象C語(yǔ)言一樣,Lua提供了相當(dāng)多的標(biāo)準(zhǔn)函數(shù)來(lái)增強(qiáng)語(yǔ)言的功能。使用這些標(biāo)準(zhǔn)函數(shù),你可以很方便的操作各種數(shù)據(jù)類型,并處理輸入輸出。有關(guān)這方面的信息,你可以參考《Programming in Lua 》一書,你可以在網(wǎng)絡(luò)上直接觀看電子版,網(wǎng)址為:
http://www.lua.org/pil/index.html 當(dāng)然,Lua的最強(qiáng)大的功能是能與宿主程序親蜜無(wú)間的合作,因此,下一篇文章,我會(huì)告訴大家,如何在你的程序中使用Lua語(yǔ)言作為腳本,使你的程序和Lua腳本進(jìn)行交互。
作者: 沐楓 (第二人生成員)
版權(quán)所有轉(zhuǎn)載請(qǐng)注明原出處
主頁(yè):第二人生
http://www.d2-life.com http://www.d2-life.com/LBS/blogview.asp?logID=41為什么要用Lua作腳本?
使用Lua作腳本,主要是因?yàn)樗∏闪岘嚕w積小,運(yùn)行快),而且它的語(yǔ)法又比較簡(jiǎn)單明了。不過(guò),使用LuaAPI將Lua引擎集成到程序中,確實(shí)有一些不方便——用落木隨風(fēng)網(wǎng)友的話來(lái)說(shuō),就是"就象用匯編"。當(dāng)然,現(xiàn)在你不用再這么辛苦了,因?yàn)槟憧梢允褂肔uaWrapper For C++。使用這個(gè)工具,在C++中集成Lua腳本就是輕而易舉的事。你原有的C++函數(shù)和類,幾乎不需要任何改變,就可以與Lua腳本共享。
我們接下來(lái),用實(shí)例來(lái)說(shuō)明,如何用LuaWrapper來(lái)集成Lua腳本到你的程序中去。
1. 創(chuàng)建Lua引擎
LuaWrap lua; 或者 LuaWrap* lua = new LuaWrap;
創(chuàng)建一個(gè)LuaWrap對(duì)象,就是創(chuàng)建一個(gè)Lua腳本引擎。并且根據(jù)Lua的特性,你可以創(chuàng)建任意多個(gè)Lua引擎,甚至可以分布在不同的線程當(dāng)中。
2. 裝載并執(zhí)行腳本程序
你可以從緩沖區(qū)中裝載Lua腳本:
lua.LoadString(
"print('Hello World')"
);
當(dāng)然,你也可以從文件中裝入,并執(zhí)行Lua腳本:
Lua.LoadFile("./test.lua");
Lua的腳本,可以是源代碼,也可以經(jīng)過(guò)編譯后的中間代碼。也許你對(duì)編譯后的中間代碼更感興趣——如果你不希望讓源代碼赤裸裸的袒露在大家的眼前。
3. 獲取和設(shè)置Lua變量
能夠獲取和設(shè)置腳本變量的內(nèi)容,是一個(gè)最基本的功能。你可以使用GetGlobal和SetGlobal函數(shù)來(lái)做到這一點(diǎn):
(1) 獲取變量:
int a = lua.GetGlobal<int>("a");
LuaTable table = lua.GetGlobal<LuaTable>("t");
這里,<> 里頭的類型,就是想要的變量的類型。
(2) 設(shè)置變量:
lua.SetGlobal("a", a);
lua.SetGlobal("t", table);
4. 調(diào)用Lua函數(shù)
使用Call函數(shù),就可以很簡(jiǎn)單的從你的程序中調(diào)用Lua函數(shù):
lua.Call<void>("print", "Hello World");
int sum = lua.Call<int>("add", 2, 3);
這里,<> 里頭的類型是返回值的類型。
5. 如何讓Lua也能調(diào)用C++的函數(shù)
精采的地方來(lái)了。假如有下面這樣的一個(gè)函數(shù):
int add(int a, int b)
{
return a + b;
}
如果想讓它能夠讓Lua使用,只需將它注冊(cè)到Lua引擎當(dāng)中就可以了:
lua.RegisterFunc("add", int(int,int), add);
這樣,Lua中就可以用直接使用了:
(Lua腳本)sum = add(1, 3)
(*) RegisterFunc的功能,就是讓你把C++的函數(shù)注冊(cè)到Lua中,供Lua腳本使用。
第一個(gè)參數(shù),是想要在Lua中用的函數(shù)名。
第二個(gè)參數(shù),是C++中函數(shù)的原型; C++允許函數(shù)重載的,你可以使用函數(shù)原型,來(lái)選擇需要注冊(cè)到Lua引擎中的那個(gè)函數(shù)。
第三個(gè)參數(shù),就是C++中函數(shù)的指針了。
6. 如何能讓C++的類在Lua中使用
我們先看看下面這個(gè)C++類:
class MyArray
{
std::vector<double> array;
public:
void setvalue(int index, double value);
double getvalue(int index);
int size();
const char* ToString();
};
你準(zhǔn)備要讓Lua能夠自由訪問(wèn)并操作這個(gè)類。很簡(jiǎn)單,你只需增加幾個(gè)宏定義就可以了:
class MyArray
{
std::vector<double> array;
public:
void setvalue(int index, double value);
double getvalue(int index);
int size();
const char* ToString();
// 將一個(gè) class 作為一個(gè) Lua 對(duì)象是很容易的,只需要增加以下宏定義。
DEFINE_TYPENAME("My.array");
BEGIN_REGLUALIB("array")
LUALIB_ITEM_create("new", MyArray ) // 創(chuàng)建MyArray (注:由于發(fā)表的原因,create應(yīng)為全部大寫)
LUALIB_ITEM_DESTROY("del", MyArray ) // 消除MyArray。
END_REGLUALIB()
BEGIN_REGLUALIB_MEMBER()
LUALIB_ITEM_FUNC("size", int (MyArray*), &MyArray::size)
LUALIB_ITEM_FUNC("__getindex", double(MyArray*, int), &MyArray::getvalue)
LUALIB_ITEM_FUNC("__newindex", void (MyArray*, int, double), &MyArray::setvalue)
LUALIB_ITEM_FUNC("__tostring", const char* (MyArray*), &MyArray::ToString)
LUALIB_ITEM_DESTROY("__gc", MyArray ) // 垃圾收集時(shí)消除對(duì)象用。
END_REGLUALIB_MEMBER()
};
只要有了這些宏定義,這個(gè)類就是可以在Lua中使用的類了,我們就可以在Lua中注冊(cè)這個(gè)類了:
lua.Register<MyArray>()
這樣注冊(cè)以后,我們?cè)贚ua中就可以使用這個(gè)類了:
a = array.new() -- 創(chuàng)建對(duì)象,相當(dāng)于 a = new Myarray
a[1] = 10 -- 調(diào)用__newindex,也就是C++中的 a->setvalue(1, 10)
a[2] = 20 -- 調(diào)用__newindex,也就是C++中的 a->setvalue(2, 20)
print(
a, -- 調(diào)用 __tostring,也就是C++中的 a->ToString()
a:size(), -- 相當(dāng)于C++中的 a->size()
a[1], -- 調(diào)用__getindex,也就是C++中的a->getvalue(1)
a[2]) --調(diào)用__getindex,也就是C++中的a->getvalue(2)
array.del(a) -- 清除對(duì)象,相當(dāng)于 delete a
a = nil -- 清空 a,很象C++中的 a = NULL
當(dāng)然,你也可以不用del這個(gè)對(duì)象,而是等待Lua幫你自動(dòng)進(jìn)行垃圾回收。在Lua進(jìn)行垃圾回收時(shí),它會(huì)自動(dòng)調(diào)用這個(gè)對(duì)象的 __gc ,相當(dāng)于 delete。
那么,在C++中要?jiǎng)?chuàng)建MyArray對(duì)象,并且傳遞給Lua全局變量怎么辦?就象前面講過(guò)的一樣,使用SetGlobal:
MyArray* a = new MyArray;
lua.SetGlobal("a", a);
要獲取該對(duì)象,同樣的,應(yīng)該使用GetGlobal:
MyArray* a = lua.GetGlobal<MyArray>("a");
對(duì)于傳遞給Lua的對(duì)象,就讓Lua來(lái)管理該對(duì)象的生存周期好了。如果你非要?jiǎng)h除它的話,你可以使用DelGlobalObject:
lua.DelGlobalObject<MyArray>("a");
不過(guò)這么做的話,你應(yīng)當(dāng)明白你在做什么,因?yàn)樵贚ua的腳本中,可能已經(jīng)在多處引用了這個(gè)對(duì)象了。刪除了其中一個(gè),將導(dǎo)致其它引用對(duì)象失效,從而可能引致系統(tǒng)崩潰。
(1) DEFINE_TYPENAME("My.array");
定義類型的名稱。在Lua中,這個(gè)類型名稱是唯一用來(lái)識(shí)別C++類型的,你必須為不同的對(duì)象給予不同的名稱。
(2) BEGIN_REGLUALIB("array") … END_REGLUALIB()
你可以為一個(gè)對(duì)象定義一個(gè)程序庫(kù),"array"就是程序庫(kù)的名字。在程序庫(kù)中定義的函數(shù)是全局函數(shù),在Lua中,使用該函數(shù),需要在函數(shù)前加上庫(kù)的名字,如:array.new()。通常,程序庫(kù)會(huì)包含創(chuàng)建對(duì)象的方法。如:
LUALIB_ITEM_create("new", MyArray ) // 創(chuàng)建MyArray (注:由于發(fā)表的原因,create應(yīng)為全部大寫)
這樣子,你才能在Lua中創(chuàng)建MyArray:
a = array.new()
你也可以選擇增加一個(gè)刪除對(duì)象操作:
LUALIB_ITEM_DESTROY("del", MyArray ) // 刪除MyArray
這樣,你就可以直接刪除一個(gè)對(duì)象了:
array.del(a)
(3) BEGIN_REGLUALIB_MEMBER() …END_REGLUALIB_MEMBER()
在此處,你可以定義對(duì)象的成員函數(shù),也可以重載對(duì)象的操作符——是的,就象C++的operator重載。例如:
LUALIB_ITEM_FUNC("__newindex", void (MyArray*, int, double), &MyArray::setvalue)
就是重載 operator[] 操作符。Lua中可重載的操作符還有許多,如:
__getindex:操作符[],支持讀取訪問(wèn),如 v = a[10]
__newindex:操作符[],支持賦值訪問(wèn),如 a[10] = 1.22
__tostring:將變量轉(zhuǎn)換成字串__add:等同于operator +
__add:操作符 +
__sub:操作符 –
__mul:操作符 ×
__div:操作符 ÷
__pow:操作符 ^ (乘方)
__unm:一元操作符 –
__concat:操作符 .. (字符串連接)
__eq:操作符 == (a ~= b等價(jià)于 not a == b)
__lt:操作符 < (a > b 等價(jià)于 b < a)
__le:操作符 <= (a >= b 等價(jià)于 b <= a,要注意的是,如果沒(méi)有定義"__le",則Lua將會(huì)嘗試將a<=b 轉(zhuǎn)換成 not (b < a) )
__gc:在垃圾回收時(shí)調(diào)用此函數(shù),相當(dāng)于C++的析構(gòu)函數(shù)。強(qiáng)烈建議定義此操作符,以免造成內(nèi)存泄漏等情況。比如:
LUALIB_ITEM_DESTROY("__gc", MyArray ) // 垃圾收集時(shí)消除對(duì)象用。
(注) 這里要說(shuō)明一下,在lua中,訪問(wèn)索引操作符是__index,不是__getindex,在luaWrapper庫(kù)中,為了方便使用,將其映射為_(kāi)_getindex,同時(shí),對(duì)__index的定義將會(huì)被忽略。
就這么簡(jiǎn)單。假如你已經(jīng)有現(xiàn)成的類,而你沒(méi)有修改該類的權(quán)力,如何將其加入到Lua中呢?答案就是,繼承它,將把派生類加入到Lua中。
結(jié)束語(yǔ)
LuaWrapper 需要用到boost庫(kù)的支持:boost/type_traits.hpp, boost/function.hpp, boost/bind.hpp,它使用了C++的模板部份特化,因此,C++編譯器如果不支持此特性,將無(wú)法編譯。目前支持此特性的編譯器已經(jīng)有很多。在VisualStudo產(chǎn)品系列中,只有VC7.1能支持此特性,因此,您如果正在使用VisualStudio,請(qǐng)確認(rèn)你用的是VisualStudio2003。
如果你覺(jué)得 LuaWrapper For C++ 能夠幫助你,我會(huì)感覺(jué)很榮幸。我很愿意將這個(gè)程序庫(kù)分享給大家。順便一提的是,如果你在使用過(guò)程中發(fā)現(xiàn)BUG,或是有好的建議,希望您能與我聯(lián)系。你在使用過(guò)程中,請(qǐng)不要?jiǎng)h除文件中的署名信息;如果你修改了程序庫(kù),請(qǐng)您在修改的文件中加入您的修改說(shuō)明。當(dāng)然,我會(huì)非常歡迎您能將修改后的程序回饋給我。我會(huì)繼續(xù)優(yōu)化并完善它。
=============================================================
File: Click Here Download: LuaWrapper For C++
File: Click Here Download: LuaWrapper test program
一.Hello World
1.前言
偶最近在學(xué)習(xí)Lua, 所以寫出心得和大家共享, 爭(zhēng)取一天寫一篇, 嘿嘿.
才開(kāi)始學(xué)所以內(nèi)容很淺, 希望大家包涵.
Lua是一種完全免費(fèi)的腳本語(yǔ)言, 可以和C/C++語(yǔ)言緊密結(jié)合,
它的官方網(wǎng)站在http://www.lua.org. 在網(wǎng)站上可以下載到lua的源碼, 沒(méi)有可
執(zhí)行版本, 不過(guò)不用擔(dān)心, 因?yàn)閘ua源碼可以在任何一種C/C++的編譯器上編譯.
如果要學(xué)習(xí)Lua, 官方網(wǎng)站上的Reference是必備的,上面有每個(gè)命令的用法,非常詳細(xì)。
參考手冊(cè) http://www.lua.org/manual/5.0/
作者寫的Programming in Lua http://www.lua.org/pil/
2.編譯 如果用的VC6, 可以下載所需的project文件,地址在
http://sourceforge.net/project/showfiles.php?group_id=32250&package_id=115604
VSNET2003可以下載這個(gè)sln文件http://home.comcast.net/~vertigrated/lua/vs7.zip
偶用的是cygwin和linux, 打入以下命令即可,
tar -zxvf lua-5.0.2.tar.gz
cd lua-5.0.2
sh ./configure
make
這樣就OK了。
為了以后使用方便,最好把bin目錄加入到path里面。
3."Hello, world!" 現(xiàn)在開(kāi)始偶們的第一個(gè)小程序"Hello, world!"
把以下程序打入文件e01.lua
例1:e01.lua
-- Hello World in Lua
print("Hello World.")
Lua有兩種執(zhí)行方式,一種是嵌入到C程序中執(zhí)行,還有一種是直接從命令行方式下執(zhí)行。
這里為了調(diào)試方便,采用第二種方式,執(zhí)行命令 lua e01.lua
輸出結(jié)果應(yīng)該是:
Hello World.
4.程序說(shuō)明 第一行 -- Hello World in Lua
這句是注釋,其中--和C++中的//意思是一樣的
第二行 print("Hello World.")
調(diào)用lua內(nèi)部命令print,輸出"Hello World."字符串到屏幕,Lua中的字符串全部是由"括起來(lái)的。
這個(gè)命令是一個(gè)函數(shù)的調(diào)用,print是lua的一個(gè)函數(shù),而"Hello World."是print的參數(shù)。
5.試試看 在Lua中有不少字符串的處理操作,本次的課后試試看的內(nèi)容就是,找出連接兩個(gè)字符串的操作,
并且print出來(lái)。
二.流程控制1. 函數(shù)的使用
以下程序演示了如何在Lua中使用函數(shù), 及局部變量
例e02.lua
-- functions
function pythagorean(a, b)
local c2 = a^2 + b^2
return sqrt(c2)
end
print(pythagorean(3,4))
運(yùn)行結(jié)果
5
程序說(shuō)明
在Lua中函數(shù)的定義格式為:
function 函數(shù)名(參數(shù))
...
end
與Pascal語(yǔ)言不同, end不需要與begin配對(duì), 只需要在函數(shù)結(jié)束后打個(gè)end就可以了.
本例函數(shù)的作用是已知直角三角形直角邊, 求斜邊長(zhǎng)度. 參數(shù)a,b分別表示直角邊長(zhǎng),
在函數(shù)內(nèi)定義了local形變量用于存儲(chǔ)斜邊的平方. 與C語(yǔ)言相同, 定義在函數(shù)內(nèi)的代
碼不會(huì)被直接執(zhí)行, 只有主程序調(diào)用時(shí)才會(huì)被執(zhí)行.
local表示定義一個(gè)局部變量, 如果不加local剛表示c2為一個(gè)全局變量, local的作用域
是在最里層的end和其配對(duì)的關(guān)鍵字之間, 如if ... end, while ... end等。全局變量的
作用域是整個(gè)程序。
2. 循環(huán)語(yǔ)句 例e03.lua
-- Loops
for i=1,5 do
print("i is now " .. i)
end
運(yùn)行結(jié)果
i is now 1
i is now 2
i is now 3
i is now 4
i is now 5
程序說(shuō)明
這里偶們用到了for語(yǔ)句
for 變量 = 參數(shù)1, 參數(shù)2, 參數(shù)3 do
循環(huán)體
end
變量將以參數(shù)3為步長(zhǎng), 由參數(shù)1變化到參數(shù)2
例如:
for i=1,f(x) do print(i) end
for i=10,1,-1 do print(i) end
這里print("i is now " .. i)中,偶們用到了..,這是用來(lái)連接兩個(gè)字符串的,
偶在(1)的試試看中提到的,不知道你們答對(duì)了沒(méi)有。
雖然這里i是一個(gè)整型量,Lua在處理的時(shí)候會(huì)自動(dòng)轉(zhuǎn)成字符串型,不需偶們費(fèi)心。
3. 條件分支語(yǔ)句 例e04.lua
-- Loops and conditionals
for i=1,5 do
print(“i is now “ .. i)
if i < 2 then
print(“small”)
elseif i < 4 then
print(“medium”)
else
print(“big”)
end
end
運(yùn)行結(jié)果
i is now 1
small
i is now 2
medium
i is now 3
medium
i is now 4
big
i is now 5
big
程序說(shuō)明
if else用法比較簡(jiǎn)單, 類似于C語(yǔ)言, 不過(guò)此處需要注意的是整個(gè)if只需要一個(gè)end,
哪怕用了多個(gè)elseif, 也是一個(gè)end.
例如
if op == "+" then
r = a + b
elseif op == "-" then
r = a - b
elseif op == "*" then
r = a*b
elseif op == "/" then
r = a/b
else
error("invalid operation")
end
4.試試看 Lua中除了for循環(huán)以外, 還支持多種循環(huán), 請(qǐng)用while...do和repeat...until改寫本文中的for程序
三.Lua數(shù)據(jù)結(jié)構(gòu) 1.簡(jiǎn)介 Lua語(yǔ)言只有一種基本數(shù)據(jù)結(jié)構(gòu), 那就是table, 所有其他數(shù)據(jù)結(jié)構(gòu)如數(shù)組啦,
類啦, 都可以由table實(shí)現(xiàn).
例e05.lua
-- Arrays
myData = {}
myData[0] = “foo”
myData[1] = 42
-- Hash tables
myData[“bar”] = “baz”
-- Iterate through the
-- structure
for key, value in myData do
print(key .. “=“ .. value)
end
輸出結(jié)果
0=foo
1=42
bar=baz
程序說(shuō)明
首先定義了一個(gè)table myData={}, 然后用數(shù)字作為下標(biāo)賦了兩個(gè)值給它. 這種
定義方法類似于C中的數(shù)組, 但與數(shù)組不同的是, 每個(gè)數(shù)組元素不需要為相同類型,
就像本例中一個(gè)為整型, 一個(gè)為字符串.
程序第二部分, 以字符串做為下標(biāo), 又向table內(nèi)增加了一個(gè)元素. 這種table非常
像STL里面的map. table下標(biāo)可以為L(zhǎng)ua所支持的任意基本類型, 除了nil值以外.
Lua對(duì)Table占用內(nèi)存的處理是自動(dòng)的, 如下面這段代碼
a = {}
a["x"] = 10
b = a -- `b' refers to the same table as `a'
print(b["x"]) --> 10
b["x"] = 20
print(a["x"]) --> 20
a = nil -- now only `b' still refers to the table
b = nil -- now there are no references left to the table
b和a都指向相同的table, 只占用一塊內(nèi)存, 當(dāng)執(zhí)行到a = nil時(shí), b仍然指向table,
而當(dāng)執(zhí)行到b=nil時(shí), 因?yàn)闆](méi)有指向table的變量了, 所以Lua會(huì)自動(dòng)釋放table所占內(nèi)存
3.Table的嵌套 Table的使用還可以嵌套,如下例
例e06.lua
-- Table ‘constructor’
myPolygon = {
color=“blue”,
thickness=2,
npoints=4;
{x=0, y=0},
{x=-10, y=0},
{x=-5, y=4},
{x=0, y=4}
}
-- Print the color
print(myPolygon[“color”])
-- Print it again using dot
-- notation
print(myPolygon.color)
-- The points are accessible
-- in myPolygon[1] to myPolygon[4]
-- Print the second point’s x
-- coordinate
print(myPolygon[2].x)
程序說(shuō)明 首先建立一個(gè)table, 與上一例不同的是,在table的constructor里面有{x=0,y=0},
這是什么意思呢? 這其實(shí)就是一個(gè)小table, 定義在了大table之內(nèi), 小table的
table名省略了.
最后一行myPolygon[2].x,就是大table里面小table的訪問(wèn)方式.
四.函數(shù)的調(diào)用 1.不定參數(shù) 例e07.lua
-- Functions can take a
-- variable number of
-- arguments.
function funky_print (...)
for i=1, arg.n do
print("FuNkY: " .. arg[i])
end
end
funky_print("one", "two")
運(yùn)行結(jié)果
FuNkY: one
FuNkY: two
程序說(shuō)明
* 如果以...為參數(shù), 則表示參數(shù)的數(shù)量不定.
* 參數(shù)將會(huì)自動(dòng)存儲(chǔ)到一個(gè)叫arg的table中.
* arg.n中存放參數(shù)的個(gè)數(shù). arg[]加下標(biāo)就可以遍歷所有的參數(shù).
2.以table做為參數(shù) 例e08.lua
-- Functions with table
-- parameters
function print_contents(t)
for k,v in t do
print(k .. "=" .. v)
end
end
print_contents{x=10, y=20}
運(yùn)行結(jié)果
x=10
y=20
程序說(shuō)明
* print_contents{x=10, y=20}這句參數(shù)沒(méi)加圓括號(hào), 因?yàn)橐詥蝹€(gè)table為參數(shù)的時(shí)候, 不需要加圓括號(hào)
* for k,v in t do 這個(gè)語(yǔ)句是對(duì)table中的所有值遍歷, k中存放名稱, v中存放值
3.把Lua變成類似XML的數(shù)據(jù)描述語(yǔ)言 例e09.lua
function contact(t)
-- add the contact ‘t’, which is
-- stored as a table, to a database
end
contact {
name = "Game Developer",
email = "hack@ogdev.net",
url = "http://www.ogdev.net",
quote = [[
There are
10 types of people
who can understand binary.]]
}
contact {
-- some other contact
}
程序說(shuō)明
* 把function和table結(jié)合, 可以使Lua成為一種類似XML的數(shù)據(jù)描述語(yǔ)言
* e09中contact{...}, 是一種函數(shù)的調(diào)用方法, 不要弄混了
* [[...]]是表示多行字符串的方法
* 當(dāng)使用C API時(shí)此種方式的優(yōu)勢(shì)更明顯, 其中contact{..}部分可以另外存成一配置文件
4.試試看 想想看哪些地方可以用到例e09中提到的配置方法呢?
五.Lua與C的交互 1.簡(jiǎn)介 Lua與C/C++結(jié)合是很緊密的, Lua與C++交互是建立在Lua與C的基礎(chǔ)上的, 所
以偶先從Lua與C講起.
正如第一講所說(shuō), 運(yùn)行Lua程序或者說(shuō)調(diào)用Lua主要有兩種方式:
* 通過(guò)命令行執(zhí)行"Lua"命令
* 通過(guò)Lua的C庫(kù)
雖然此前偶們一直用第一種方式, 但偶要告訴你, 通過(guò)Lua的C庫(kù)執(zhí)行才是游戲中
常用的方式.
2.Lua的C庫(kù) Lua的C庫(kù)可以做為Shared Library調(diào)用, 但一般開(kāi)發(fā)游戲時(shí)會(huì)把Lua的所有源程序
都包含在內(nèi), 并不把Lua編譯成共享庫(kù)的形式. 因?yàn)長(zhǎng)ua程序只有100多K, 而且?guī)缀?br> 可以在任何編譯器下Clean Compile. 帶Lua源程序的另一個(gè)好處時(shí), 可以隨時(shí)對(duì)Lua
本身進(jìn)行擴(kuò)充, 增加偶們所需的功能.
Lua的C庫(kù)提供一系列API:
* 管理全局變量
* 管理tables
* 調(diào)用函數(shù)
* 定義新函數(shù), 這也可以完全由C實(shí)現(xiàn)
* 垃圾收集器Garbage collector, 雖然Lua可以自動(dòng)進(jìn)行, 但往往不是立即執(zhí)行的,
所以對(duì)實(shí)時(shí)性要求比較高的程序, 會(huì)自己調(diào)用垃圾收集器
* 載入并執(zhí)行Lua程序, 這也可以由Lua自身實(shí)現(xiàn)
* 任何Lua可以實(shí)現(xiàn)的功能, 都可以通過(guò)Lua的C API實(shí)現(xiàn), 這對(duì)于優(yōu)化程序的運(yùn)行速度
有幫助. 經(jīng)常調(diào)用的共用的Lua程序片斷可以轉(zhuǎn)成C程序, 以提高效率. 連Lua都是C寫的
還有什么C不能實(shí)現(xiàn)呢?
3.Lua與C集成的例子 例e10.c
/* A simple Lua interpreter. */
#include
#include
int main(int argc, char *argv[]) {
char line[BUFSIZ];
lua_State *L = lua_open(0);
while (fgets(line, sizeof(line), stdin) != 0)
lua_dostring(L, line);
lua_close(L);
return 0;
}
編譯
Linux/Cygwin
* 先編譯Lua, 并把頭文件放入include路徑
* gcc e10.c -llua -llualib -o e10
VC6/VC2003
* 先編譯Lua, 在Option中設(shè)置頭文件和庫(kù)文件路徑
* 新建工程,在工程配置中加入附加庫(kù)lua.lib和lualib.lib
* 編譯成exe
運(yùn)行結(jié)果
本程序的功能是實(shí)現(xiàn)一個(gè)Lua解釋器, 輸入的每行字符都會(huì)被解釋成Lua并執(zhí)行.
程序說(shuō)明
* #include 包含lua頭文件, 然后才可以使用API
* lua_State *L = lua_open(0) 打開(kāi)一個(gè)Lua執(zhí)行器
* fgets(line, sizeof(line), stdin) 從標(biāo)準(zhǔn)輸入里讀入一行
* lua_dostring(L, line) 執(zhí)行此行
* lua_close(L) 關(guān)閉Lua執(zhí)行器
例e11.c
/* Another simple Lua interpreter. */
#include
#include
#include
int main(int argc, char *argv[]) {
char line[BUFSIZ];
lua_State *L = lua_open(0);
lua_baselibopen(L);
lua_iolibopen(L);
lua_strlibopen(L);
lua_mathlibopen(L);
while (fgets(line, sizeof(line), stdin) != 0)
lua_dostring(L, line);
lua_close(L);
return 0;
}
運(yùn)行結(jié)果
本程序的功能是實(shí)現(xiàn)一個(gè)Lua解釋器, 輸入的每行字符都會(huì)被解釋成Lua并執(zhí)行.
與上例不同的是, 本例調(diào)用了Lua的一些標(biāo)準(zhǔn)庫(kù).
程序說(shuō)明
* #include 包含Lua的標(biāo)準(zhǔn)庫(kù)
* 以下這幾行是用來(lái)讀入Lua的一些庫(kù), 這樣偶們的Lua程序就可以有更多的功能.
lua_baselibopen(L);
lua_iolibopen(L);
lua_strlibopen(L);
lua_mathlibopen(L);
4.試試看
把上面兩個(gè)小例子在你熟悉的編譯器中編譯執(zhí)行, 并試試能否與Lua源碼樹(shù)一起編譯
六.C/C++中用Lua函數(shù)
1.簡(jiǎn)介
偶們這次主要說(shuō)說(shuō)怎么由Lua定義函數(shù), 然后在C或者C++中調(diào)用. 這里偶們
暫不涉及C++的對(duì)象問(wèn)題, 只討論調(diào)用函數(shù)的參數(shù), 返回值和全局變量的使用.
2.程序
這里偶們?cè)趀12.lua里先定義一個(gè)簡(jiǎn)單的add(), x,y為加法的兩個(gè)參數(shù),
return 直接返回相加后的結(jié)果.
例e12.lua
-- add two numbers
function add ( x, y )
return x + y
end
在前一次里, 偶們說(shuō)到 lua_dofile() 可以直接在C中執(zhí)行l(wèi)ua文件. 因?yàn)榕紓?br> 這個(gè)程序里只定義了一個(gè)add()函數(shù), 所以程序執(zhí)行后并不直接結(jié)果, 效果相當(dāng)
于在C中定義了一個(gè)函數(shù)一樣.
Lua的函數(shù)可以有多個(gè)參數(shù), 也可以有多個(gè)返回值, 這都是由棧(stack)實(shí)現(xiàn)的.
需要調(diào)用一個(gè)函數(shù)時(shí), 就把這個(gè)函數(shù)壓入棧, 然后順序壓入所有參數(shù), 然后用
lua_call()調(diào)用這個(gè)函數(shù). 函數(shù)返回后, 返回值也是存放在棧中. 這個(gè)過(guò)程和
匯編執(zhí)行函數(shù)調(diào)用的過(guò)程是一樣的.
例e13.cpp 是一個(gè)調(diào)用上面的Lua函數(shù)的例子
#include
extern "C" { // 這是個(gè)C++程序, 所以要extern "C",
// 因?yàn)閘ua的頭文件都是C格式的
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
/* the Lua interpreter */
lua_State* L;
int luaadd ( int x, int y )
{
int sum;
/* the function name */
lua_getglobal(L, "add");
/* the first argument */
lua_pushnumber(L, x);
/* the second argument */
lua_pushnumber(L, y);
/* call the function with 2
arguments, return 1 result */
lua_call(L, 2, 1);
/* get the result */
sum = (int)lua_tonumber(L, -1);
lua_pop(L, 1);
return sum;
}
int main ( int argc, char *argv[] )
{
int sum;
/* initialize Lua */
L = lua_open();
/* load Lua base libraries */
lua_baselibopen(L);
/* load the script */
lua_dofile(L, "e12.lua");
/* call the add function */
sum = luaadd( 10, 15 );
/* print the result */
printf( "The sum is %d\n", sum );
/* cleanup Lua */
lua_close(L);
return 0;
}
程序說(shuō)明:
main中過(guò)程偶們上次已經(jīng)說(shuō)過(guò)了, 所以這次只說(shuō)說(shuō)luaadd的過(guò)程
* 首先用lua_getglobal()把a(bǔ)dd函數(shù)壓棧
* 然后用lua_pushnumber()依次把x,y壓棧
* 然后調(diào)用lua_call(), 并且告訴程序偶們有兩個(gè)參數(shù)一個(gè)返回值
* 接著偶們從棧頂取回返回值, 用lua_tonumber()
* 最后偶們用lua_pop()把返回值清掉
運(yùn)行結(jié)果:
The sum is 25
編譯方法
Linux下把程序存成e13.cpp
g++ e13.cpp -llua -llualib -o e13
./e13
VC下編譯方法
* 首先建立一個(gè)空的Win32 Console Application Project
* 把e13.cpp加入工程中
* 點(diǎn)project setting,然后設(shè)置link選項(xiàng), 再加上lua.lib lualib.lib兩個(gè)額外的庫(kù)
* 最后編譯
建立好的project可以在這里下載
VC http://tonyandpaige.com/tutorials/luaadd.zip
Linux http://tonyandpaige.com/tutorials/luaadd.tar.gz
3.全局變量
上面偶們用到了lua_getglobal()但并沒(méi)有詳細(xì)講, 這里偶們?cè)倥e兩個(gè)小例子來(lái)說(shuō)下全局變量
lua_getglobal()的作用就是把lua中全局變量的值壓入棧
lua_getglobal(L, "z");
z = (int)lua_tonumber(L, 1);
lua_pop(L, 1);
假設(shè)Lua程序中定義了一個(gè)全局變量z, 這段小程序就是把z的值取出放入C的變量z中.
另外Lua中還有一個(gè)對(duì)應(yīng)的函數(shù)lua_setglobal(), 作用是用棧頂?shù)闹堤畛渲付ǖ娜肿兞?br> lua_pushnumber(L, 10);
lua_setglobal(L, "z");
例如這段小程序就是把lua中的全局變量z設(shè)為10, 如果lua中未定義z的話, 就會(huì)自動(dòng)創(chuàng)建一個(gè)
全局變量z并設(shè)為10.
4.試試看
自己寫個(gè)函數(shù)用C/C++來(lái)調(diào)用下試試
七.調(diào)用C/C++函數(shù)
1.前言
上次偶說(shuō)到從C/C++中調(diào)用Lua的函數(shù), 然后就有朋友問(wèn)從Lua中如何調(diào)用C/C++的
函數(shù), 所以偶們這次就來(lái)說(shuō)說(shuō)這個(gè)問(wèn)題. 首先偶們會(huì)在C++中建立一個(gè)函數(shù), 然后
告知Lua有這個(gè)函數(shù), 最后再執(zhí)行它. 另外, 由于函數(shù)不是在Lua中定義的, 所以
無(wú)法確定函數(shù)的正確性, 可能在調(diào)用過(guò)程中會(huì)出錯(cuò), 因此偶們還會(huì)說(shuō)說(shuō)Lua出錯(cuò)處
理的問(wèn)題.
2.Lua中調(diào)用C函數(shù)
在lua中是以函數(shù)指針的形式調(diào)用函數(shù), 并且所有的函數(shù)指針都必須滿足如下此種
類型:
typedef int (*lua_CFunction) (lua_State *L);
也就是說(shuō), 偶們?cè)贑++中定義函數(shù)時(shí)必須以lua_State為參數(shù), 以int為返回值才能
被Lua所調(diào)用. 但是不要忘記了, 偶們的lua_State是支持棧的, 所以通過(guò)棧可以
傳遞無(wú)窮個(gè)參數(shù), 大小只受內(nèi)存大小限制. 而返回的int值也只是指返回值的個(gè)數(shù)
真正的返回值都存儲(chǔ)在lua_State的棧中. 偶們通常的做法是做一個(gè)wrapper, 把
所有需要調(diào)用的函數(shù)都wrap一下, 這樣就可以調(diào)用任意的函數(shù)了.
下面這個(gè)例子是一個(gè)C++的average()函數(shù), 它將展示如何用多個(gè)參數(shù)并返回多個(gè)值
例e14.cpp
#include
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
/* the Lua interpreter */
lua_State* L;
static int average(lua_State *L)
{
/* get number of arguments */
int n = lua_gettop(L);
double sum = 0;
int i;
/* loop through each argument */
for (i = 1; i <= n; i++)
{
/* total the arguments */
sum += lua_tonumber(L, i);
}
/* push the average */
lua_pushnumber(L, sum / n);
/* push the sum */
lua_pushnumber(L, sum);
/* return the number of results */
return 2;
}
int main ( int argc, char *argv[] )
{
/* initialize Lua */
L = lua_open();
/* load Lua base libraries */
lua_baselibopen(L);
/* register our function */
lua_register(L, "average", average);
/* run the script */
lua_dofile(L, "e15.lua");
/* cleanup Lua */
lua_close(L);
return 0;
}
例e15.lua
-- call a C++ function
avg, sum = average(10, 20, 30, 40, 50)
print("The average is ", avg)
print("The sum is ", sum)
程序說(shuō)明:
* lua_gettop()的作用是返回棧頂元素的序號(hào). 由于Lua的棧是從1開(kāi)始編號(hào)的,
所以棧頂元素的序號(hào)也相當(dāng)于棧中的元素個(gè)數(shù). 在這里, 棧中元素的個(gè)數(shù)就
是傳入的參數(shù)個(gè)數(shù).
* for循環(huán)計(jì)算所有傳入?yún)?shù)的總和. 這里用到了數(shù)值轉(zhuǎn)換lua_tonumber().
* 然后偶們用lua_pushnumber()把平均值和總和push到棧中.
* 最后, 偶們返回2, 表示有兩個(gè)返回值.
* 偶們雖然在C++中定義了average()函數(shù), 但偶們的Lua程序并不知道, 所以需
要在main函數(shù)中加入
/* register our function */
lua_register(L, "average", average);
這兩行的作用就是告訴e15.lua有average()這樣一個(gè)函數(shù).
* 這個(gè)程序可以存成cpp也可以存成c, 如果以.c為擴(kuò)展名就不需要加extern "C"
編譯的方法偶們上次說(shuō)過(guò)了, 方法相同.
e15.lua執(zhí)行的方法只能用上例中的C++中執(zhí)行, 而不能用命令行方式執(zhí)行.
3.錯(cuò)誤處理
在上例中, 偶們沒(méi)有對(duì)傳入的參數(shù)是否為數(shù)字進(jìn)行檢測(cè), 這樣做不好. 所以這里偶
們?cè)偌由襄e(cuò)誤處理的片斷.
把這段加在for循環(huán)之內(nèi):
if (!lua_isnumber(L, i)) {
lua_pushstring(L, "Incorrect argument to 'average'");
lua_error(L);
}
這段的作用就是檢測(cè)傳入的是否為數(shù)字.
加上這段之后, 偶們debug的時(shí)候就會(huì)簡(jiǎn)單許多. 對(duì)于結(jié)合兩種語(yǔ)言的編程, 它們之
間傳遞數(shù)據(jù)的正確性檢測(cè)是非常重要的.
這里有別人寫好的例子:
VC的 http://tonyandpaige.com/tutorials/luaavg.zip
Linux的 http://tonyandpaige.com/tutorials/luaavg.tar.gz
Lua 的 5.1 版本已經(jīng)正式發(fā)布。現(xiàn)在,我們應(yīng)該把全部討論放在這個(gè)版本上。
應(yīng)該盡量使用 local 變量而非 global 變量。這是
Lua 初學(xué)者最容易犯的錯(cuò)誤。global 變量實(shí)際上是放在一張全局的 table 里的。global 變量實(shí)際上是利用一個(gè) string (變量名作 key) 去訪問(wèn)這個(gè) table 。雖然
Lua5 的 table 效率很高 ,但是相對(duì)于 local 變量,依然有很大的效率損失。local 變量是直接通過(guò)
Lua 的堆棧訪問(wèn)的。有些 global 變量的訪問(wèn)是不經(jīng)意的,比如我們有雙重循環(huán)操作一個(gè)迭代的 table:
for k1,v1 inpairs(tbl)dofor k2,v2 inpairs(v1)do
...
end
end
這里,pairs 其實(shí)是一個(gè)全局變量應(yīng)用的函數(shù)。如果我們這樣做:
dolocalpairs=pairs
for k1,v1 inpairs(tbl)dofor k2,v2 inpairs(v1)do
...
endend
end
效率會(huì)稍微提高一些。如果是單層循環(huán),這樣做就沒(méi)有意義。因?yàn)?for ... in 循環(huán)中的 pairs 這個(gè)函數(shù)只會(huì)被調(diào)用一次,而不是每次循環(huán)都去調(diào)。我們的原則其實(shí)是,被多次讀取的 global 變量,都應(yīng)該提取出來(lái)放到 local 變量中。
警惕臨時(shí)變量 字符串的連接操作,會(huì)產(chǎn)生新的對(duì)象。這是由 lua 本身的 string 管理機(jī)制導(dǎo)致的。lua 在 VM 內(nèi)對(duì)相同的 string 永遠(yuǎn)只保留一份唯一 copy ,這樣,所有字符串比較就可以簡(jiǎn)化為地址比較。這也是 lua 的 table 工作很快的原因之一。這種 string 管理的策略,跟 java 等一樣,所以跟 java 一樣,應(yīng)該盡量避免在循環(huán)內(nèi)不斷的連接字符串,比如 a = a..x 這樣。每次運(yùn)行,都很可能會(huì)生成一份新的 copy 。
同樣,記住,每次構(gòu)造一份 table 都會(huì)多一份 table 的 copy 。比如在 lua 里,把平面坐標(biāo)封裝成 { x, y } 用于參數(shù)傳遞,就需要考慮這個(gè)問(wèn)題。每次你想構(gòu)造一個(gè)坐標(biāo)對(duì)象傳遞給一個(gè)函數(shù),{ 10,20 } 這樣明確的寫出,都會(huì)構(gòu)造一個(gè)新的 table 出來(lái)。要么,我們想辦法考慮 table 的重用;要么,干脆用 x,y 兩個(gè)參數(shù)傳遞坐標(biāo)。
同樣需要注意的是以 function foo (...) 這種方式定義函數(shù), ... 這種不定參數(shù),每次調(diào)用的時(shí)候都會(huì)被定義出一個(gè) table 存放不定數(shù)量的參數(shù)。
這些臨時(shí)構(gòu)造的對(duì)象往往要到 gc 的時(shí)候才被回收,過(guò)于頻繁的 gc 有時(shí)候正是效率瓶頸。
使用 closure 代替 table 上面提到封裝坐標(biāo)的問(wèn)題。誠(chéng)然,我們可以用 { x=1,y=2 } 這樣封裝一個(gè)坐標(biāo)。不過(guò)還有一個(gè)方法可供選擇。它稍微輕量一點(diǎn)。
function point (x,y)returnfunction()return x,y end
end
-- 使用范例
p=point(1,2)print(p())-- 輸出 1 2
如果你愿意,還可以做的復(fù)雜一點(diǎn):
function point (x,y)returnfunction(idx)if idx=="x"thenreturn x
elseif idx=="y"thenreturn y
elsereturn x,y endend
end
-- 使用范例
p=point(1,2)print(p("x"))-- 1print(p("y"))-- 2
x,y 實(shí)際被存放在 closure 里,每次調(diào)用 function point 都有一份獨(dú)立的 closure。當(dāng)然,function 的 code 只有一份。
設(shè)法減少?gòu)?C 向 Lua 傳遞字符串 字符串常量在 Lua VM 內(nèi)部工作的非常快,但是一個(gè)從 C 向 lua vm 通過(guò) lua_pushstring 之類的 api 傳遞進(jìn) VM 時(shí),就需要掂量一下了。這至少包含一個(gè)再 hash 和匹配的過(guò)程。
我的 Blog 上的一篇文章討論了這個(gè)問(wèn)題。
lua 中的繼承 lua 中實(shí)現(xiàn) OO ,虛表往往設(shè)置一個(gè) metatable 并設(shè)置 __index ,而繼承則用 metatable 的 __index 把虛表串起來(lái)。當(dāng)類繼承層次過(guò)多的時(shí)候,效率比較低,那么就可以用下面這個(gè)技巧。
function inherit(sub,super)setmetatable(sub,
{ __index=function(t,k)local ret=super[k]
sub[k]=ret
return ret
end})end
利用邏輯運(yùn)算的短路效應(yīng) lua 編程中,and or 跟 C 一樣是有短路效應(yīng)的,不過(guò)他們的返回值并非 bool 類型,而是表達(dá)式中的左值或者右值。我們常常利用這個(gè)特性來(lái)簡(jiǎn)化代碼。
function foo(arg)
arg=arg or"default"
...
end
利用 or 運(yùn)算賦缺省值是最常用的技巧。上例中,如果 arg 為 nil ,arg 就會(huì)被賦值為 "default" 。但是這個(gè)技巧有個(gè)缺陷,當(dāng)缺省值是 true 的時(shí)候會(huì)有點(diǎn)問(wèn)題。
a=a ortrue-- 錯(cuò)誤的寫法,當(dāng) a 明確寫為 false 的時(shí)候,也會(huì)被改變成 true 。
a= a ~= false-- 正確的寫法,當(dāng) a 為 nil 的時(shí)候,被賦值為 true ;而 false 則不變。
另外,巧妙使用 and or 還可以實(shí)現(xiàn)類似 C 語(yǔ)言中的 ?: 三元操作:
functionmax(a,b)return a>b and a or b
end
上面這個(gè)函數(shù)可以返回 a 和 b 中較大的一個(gè),其邏輯類似 C 語(yǔ)言中的 return (a>b) ? a : b ;
我這個(gè)人記性不好,學(xué)過(guò)的東西老是愛(ài)忘,學(xué)得越多忘得越快,腦子和我可憐的硬盤一樣容量比較小,所以我發(fā)現(xiàn)我不得不把有些東西記錄下來(lái)。其實(shí)學(xué)一樣?xùn)|西關(guān)鍵在于多學(xué)多用,有道是書讀百遍其意自現(xiàn),對(duì)于我這種比較笨又沒(méi)天賦的人來(lái)說(shuō)可謂金玉良言了。
以上算前言吧,下邊才是正文。
Ogre這個(gè)引擎的效率不知道實(shí)際應(yīng)用起來(lái)如何,但是聽(tīng)說(shuō)結(jié)構(gòu)倒是比較好的。選擇它來(lái)學(xué)習(xí)主要是因?yàn)樗_(kāi)源,而且是C++和Dx寫的,關(guān)鍵還有資料比較多,國(guó)內(nèi)研究的也比較多,也有一些教程,不過(guò)Ogre不斷推出新版本,許多教程都有點(diǎn)過(guò)期了。要了解最新的使用方法還得看官方的教程。我也是直接看官方的教程,但是英文一般,每次打開(kāi)大片英文頁(yè)面看著的確比較迷糊,所以我打算把里面一些重要的關(guān)鍵部分節(jié)選出來(lái)以備參考,有時(shí)候可以快速的重溫,比如這篇要介紹的如何配置Ogre,需要記嗎?程序員記不了那么多啦,用的時(shí)候再查。當(dāng)然Ogre也在持續(xù)更新,如果我個(gè)人還在持續(xù)學(xué)習(xí)使用Ogre,那么我也會(huì)持續(xù)更新這些教程的,如果你是Ogre的使用者記得來(lái)我的Blog:http://www.shnenglu.com/singohgod 看看吧,希望能對(duì)大家有點(diǎn)幫助。
首先安裝SDK,可以編譯里面帶的示例看看一些效果展示。編譯源碼就得下載源碼吧,記得還要下一個(gè)Dependencies,解壓到源碼目錄就可以了,編譯應(yīng)該能通過(guò)的,我這里沒(méi)有遇到問(wèn)題。
不要被繁多的目錄和文件嚇著了,其實(shí)運(yùn)行Ogre程序只需要下列庫(kù)和文件:
OGRE Libraries & Files
- OGRE libraries (OgreMain[_d].dll, OgrePlatform[_d].dll or libOgreMain.so, libOgrePlatform.so for linux).
- plugins.cfg - Text file specifying the rendering libraries available to Ogre (ie DX9, OpenGL).
- All the plugin libraries listed in plugins.cfg (you can remove items from plugins.cfg if you don't wish to use them).
- resources.cfg - If using the ExampleApplication, a text file specifing paths to materials, textures, models, etc.
- OgreCore.zip - Ensure resources.cfg has the proper path to this file if you plan to use the OGRE debug panel or profiler.
- Other Resources used in your program (*.zip; *.png; *.particle; *.mesh; ...).
還需要其他的第三方庫(kù):
These are required:
- Zlib: zlib1.dll; libz.so (debian: zlib1g, zlib1g-dev)
- DevIL: devil.dll, ilu.dll, ilut.dll; libIL.so, libILU.so (debian: libdevil1, libdevil-dev)
These are optional:
- CEGUI: OgreGUIRenderer[_d].dll, CEGUIBase[_d].dll, CEGUITaharezLook[_d].dll, CEGUIWindowsLook[_d].dll, xerces-c_2_5_0.dll
- CEGUI: libCEGUIBase.so, libCEGUIOgreRenderer.so, libxerces-c.so (debian: libcegui-mk2-0, libcegui-mk2-dev, libxerces26, libxerces26-dev)
- Cg: cg.dll; libCg.so (debian: nvidia-cg-toolkit)
- OpenEXR: openexr.dll??; (debian: libopenexr-dev libopenexr2 )
- ReferenceApp: ReferenceAppLayer.dll
不同的編譯器還需要有:
Extras for Microsoft Visual C++ 6 (SP3+)
- stlport_vc6[_stldebug]46.dll
- msvcp60[D].dll
- msvcrt[D].dll
- Extras for Microsoft Visual C++.Net 2002
- stlport_vc7[_stldebug]46.dll
- msvcp70[d].dll
- msvcr70[d].dll
- Extras for Microsoft Visual C++.Net 2003
- msvcp71[d].dll
- msvcr71[d].dll
- Extras for Mingw + STLPort
- libstlport[stlg].5.0.dll
- mingwm10.dll
設(shè)置環(huán)境變量:
If you downloaded and installed the precompiled OGRE SDK, you should already have an environment variable called 'OGRE_HOME' registered already, pointing at the folder where you installed. If it isn't there you probably installed under a different user, so define OGRE_HOME manually
If you downloaded the source distribution, you should register a new environment variable OGRE_SRC pointing at the 'ogrenew' folder from the OGRE source
Ogre源碼項(xiàng)目的目錄結(jié)構(gòu):
work_dir
include
*.h
src
*.cpp
scripts
*.vcproj
新建項(xiàng)目也依據(jù)這個(gè)結(jié)構(gòu),你的項(xiàng)目應(yīng)該有這些文件夾:'bin', 'include', 'media', 'testsolution', 'scripts', and 'src'
修改新項(xiàng)目的屬性:
Debugging : Working Directory = ..\bin\Debug
C/C++ : Preprocessor : Preprocessor Definitions += _STLP_DEBUG (only in Debug mode, not needed for .Net 2003 and 2005)
C/C++ : Code Generation : Use runtime library = Multithreaded Debug DLL (Multithreaded DLL in Release)
Linker : General : Output File = ..\bin\Debug\[appname].exe
Linker : Input : Additional Dependencies += OgreMain_d.lib (OgreMain.lib in Release)
如果你是安裝SDK:
C/C++ : General : Additional Include Directories = ..\include;$(OGRE_HOME)\include;$(OGRE_HOME)\samples\include
Linker : General : Additional Library Directories = $(OGRE_HOME)\lib
如果你是編譯源碼:
C/C++ : General : Additional Include Directories = ..\include;$(OGRE_SRC)\OgreMain\include;$(OGRE_SRC)\Samples\Common\Include
Linker : General : Additional Library Directories = $(OGRE_SRC)\OgreMain\Lib\Debug
這些設(shè)置好以后你就可以新建一個(gè)SampleApp.cpp文件,然后拷貝如下代碼:
#include "ExampleApplication.h"

// Declare a subclass of the ExampleFrameListener class
class MyListener : public ExampleFrameListener


{
public:
MyListener(RenderWindow* win, Camera* cam) : ExampleFrameListener(win, cam)

{
}

bool frameStarted(const FrameEvent& evt)

{
return ExampleFrameListener::frameStarted(evt);
}

bool frameEnded(const FrameEvent& evt)

{
return ExampleFrameListener::frameEnded(evt);
}
};

// Declare a subclass of the ExampleApplication class
class SampleApp : public ExampleApplication


{
public:
SampleApp()

{
}

protected:
// Define what is in the scene
void createScene(void)

{
// put your scene creation in here
}
// Create new frame listener
void createFrameListener(void)

{
mFrameListener = new MyListener(mWindow, mCamera);
mRoot->addFrameListener(mFrameListener);
}
};

#ifdef __cplusplus

extern "C"
{
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)
#else
int main(int argc, char **argv)
#endif


{
// Instantiate our subclass
SampleApp myApp;


try
{
// ExampleApplication provides a go method, which starts the rendering.
myApp.go();
}

catch (Ogre::Exception& e)
{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "Exception:\n";
std::cerr << e.getFullDescription().c_str() << "\n";
#endif
return 1;
}

return 0;
}

#ifdef __cplusplus
}
#endif

未完!
3D圖形技術(shù)常用技術(shù)一覽
一、場(chǎng)景管理相關(guān)的技術(shù)(scene manager th):
八叉樹(shù)(octree) 、四叉樹(shù)(quadtree)、二叉樹(shù)(biniary space tree)、多叉樹(shù)(n - tree)、入口技術(shù)(portal)、擴(kuò)展入口(anti-portal)
二、通用內(nèi)核渲染管理技術(shù)(render manager)
隊(duì)列(queue)、優(yōu)先隊(duì)列(deque)、鏈表(list)
三、地形管理和繪制技術(shù)(terrain manager and render engine)
四叉樹(shù)(quadtree,和scenemanager重合)、單位地形塊管理(terrainChunk)、分塊地形(mapTile)、
二元三角樹(shù)(rometree)
四、通用不可見(jiàn)面去除技術(shù)
背面剔除(back cull)、視口截頭體剪裁(frustum)、遮擋面剔除(HBR)
五、通用動(dòng)畫技術(shù)
關(guān)鍵幀動(dòng)畫(frame animate)、骨骼蒙皮動(dòng)畫(skeleton and skin mesh animate)、頂點(diǎn)動(dòng)畫(vertex animate)、紋理動(dòng)畫(textue animate)
六、通用材質(zhì)紋理技術(shù):
單紋理(single texture)、多重紋理(multpile texture)、透明度紋理(alpha texture)、陰影貼圖(shadow map)、光照貼圖(light map)、法線貼圖(normal texture)、高動(dòng)態(tài)范圍光照?qǐng)D(high dynamic range texture,用浮點(diǎn)紋理來(lái)模擬廣泛的光照范圍)、頂點(diǎn)置換圖(displacement texture,利用法線圖、高度圖和相對(duì)偏離圖進(jìn)行物體模型的簡(jiǎn)化)、高度圖(high texture)
七、光照陰影:
光線跟蹤(ray trace)、光照?qǐng)D(light map)、陰影圖(shadow map)、動(dòng)態(tài)光照(dynamic light)、體積陰影(shadow volumn)、模板陰影(stencil shadow)、頂點(diǎn)光照(vertex light)、像素光照(pixel light)、HDR、PRT
八、雜項(xiàng):
粒子動(dòng)畫系統(tǒng),帶子動(dòng)畫系統(tǒng),3ds max\maya\lightwave\vue infinite插件
九、圖形處理器技術(shù)(GPU programming)
vs、ps、HLSL、CG
| C++資源之不完全導(dǎo)引(完整版) |
|
|
C++資源之不完全導(dǎo)引(完整版)
來(lái)源:www.csdn.net
撰文:曾毅、陶文
聲明:本文2004年5月首發(fā)于《CSDN開(kāi)發(fā)高手》,版權(quán)歸該雜志與《程序員》雜志社 所有。
------------------------------------------------------------------------ --------
|
1,前言
無(wú)數(shù)次聽(tīng)到“我要開(kāi)始學(xué)習(xí)C++!”的吶喊,無(wú)數(shù)次聽(tīng)到“C++太復(fù)雜了,我真的
學(xué)不會(huì)”的無(wú)奈。Stan Lippman先生曾在《C++ Primer》一書中指出“C++是最為難
學(xué)的高級(jí)程序設(shè)計(jì)語(yǔ)言之一”,人們常將“之一”去掉以表達(dá)自己對(duì)C++的敬畏。誠(chéng)
然,C++程序設(shè)計(jì)語(yǔ)言對(duì)于學(xué)習(xí)者的確有很多難以逾越的鴻溝,體系結(jié)構(gòu)的龐大,應(yīng)
接不暇并不斷擴(kuò)充的特性……除此之外,參考資料之多與冗雜使它的學(xué)習(xí)者望而卻
步,欲求深入者苦不堪言。希望這一份不完全導(dǎo)引能夠成為您C++學(xué)習(xí)之路上的引路
燈。
撰寫本文的初衷并不打算帶領(lǐng)大家體驗(yàn)古老的C++歷史,如果你想了解C++的歷
史與其前期發(fā)展中諸多技術(shù)的演變,你應(yīng)當(dāng)去參考Bjarne的《The Design and Evo
lution of C++》。當(dāng)然也不打算給大家一個(gè)無(wú)所不包的寶典(并非不想:其一是因
水平有限,其二無(wú)奈C++之博大精深),所給出的僅僅是一些我們認(rèn)為對(duì)于想學(xué)習(xí)C
++的廣大讀者來(lái)說(shuō)最重要并且觸手可及的開(kāi)發(fā)與學(xué)習(xí)資源。
本文介紹并分析了一些編譯器,開(kāi)發(fā)環(huán)境,庫(kù),少量的書籍以及參考網(wǎng)站,并
且盡可能嘗試著給出一個(gè)利用這些資源的導(dǎo)引,望對(duì)如同我們一樣的初學(xué)者能夠有
所裨益。
------------------------------------------------------------------------
--------
2,編譯器
在C++之外的任何語(yǔ)言中,編譯器都從來(lái)沒(méi)有受到過(guò)如此之重視。因?yàn)镃++是一
門相當(dāng)復(fù)雜的語(yǔ)言,所以編譯器也難于構(gòu)建。直到最近我們才開(kāi)始能夠使用上完全
符合C++標(biāo)準(zhǔn)的編譯器(哦,你可能會(huì)責(zé)怪那些編譯器廠商不能盡早的提供符合標(biāo)準(zhǔn)
的編譯器,這只能怪他們各自維系著自身的一套別人不愿接受的標(biāo)準(zhǔn))。什么?你
說(shuō)這無(wú)關(guān)緊要?哦,不,你所需要的是和標(biāo)準(zhǔn)化C++高度兼容的編譯環(huán)境。長(zhǎng)遠(yuǎn)來(lái)看
,只有這樣的編譯器對(duì)C++開(kāi)發(fā)人員來(lái)說(shuō)才是最有意義的工具,尤其是對(duì)于程序設(shè)計(jì)
語(yǔ)言的學(xué)習(xí)者。一至性讓代碼具備可移植性,并讓一門語(yǔ)言及其庫(kù)的應(yīng)用更為廣泛
。嗯,是的,我們這里只打算介紹一些公認(rèn)的優(yōu)秀編譯器。
2.1 Borland C++
這個(gè)是Borland C++ Builder和Borland C++ Builder X這兩種開(kāi)發(fā)環(huán)境的后臺(tái)
編譯器。(哦,我之所以將之分為兩種開(kāi)發(fā)環(huán)境你應(yīng)當(dāng)能明白為什么,正如Delphi
7到Delphi8的轉(zhuǎn)變,是革命性的兩代。)Borland C++由老牌開(kāi)發(fā)工具廠商Borland
傾力打造。該公司的編譯器素以速度快,空間效率高著稱,Borland C++ 系列編譯
器秉承了這個(gè)傳統(tǒng),屬于非常優(yōu)質(zhì)的編譯器。標(biāo)準(zhǔn)化方面早在5.5版本的編譯器中對(duì)
標(biāo)準(zhǔn)化C++的兼容就達(dá)到了92.73%。目前最新版本是Borland C++ Builder X中的6.
0版本,官方稱100%符合ANSI/ISO的C++標(biāo)準(zhǔn)以及C99標(biāo)準(zhǔn)。嗯…這正是我前面所指的
“完全符合C++標(biāo)準(zhǔn)的編譯器”。
2.2 Visual C++
這個(gè)正是我們熟知的Visual Studio 和 Visual Studio.net 2002, 2003以及2
005 Whidbey中帶的C++編譯器。由Microsoft公司研制。在Visual Studio 6.0中,
因?yàn)榫幾g器有太多地方不能與后來(lái)出現(xiàn)的C++標(biāo)準(zhǔn)相吻合而飽受批評(píng)(想想你在使用
STL的時(shí)候編譯時(shí)報(bào)出的那些令人厭惡的error和warning吧)。VC++6.0對(duì)標(biāo)準(zhǔn)化C+
+的兼容只有83.43%。但是隨著C++編譯器設(shè)計(jì)大師Stanley Lippman以及諸多C++社
群達(dá)人的加盟,在Visual Studio.NET 2003中,Visual C++編譯器已經(jīng)成為一個(gè)非
常成熟可靠的C++編譯器了。Dr.Dobb's Journal的評(píng)測(cè)顯示Visual C++7.1對(duì)標(biāo)準(zhǔn)C
++的兼容性高達(dá)98.22%,一度成為CBX之前兼容性最好的編譯器。結(jié)合強(qiáng)大的Visua
l Studio.NET開(kāi)發(fā)環(huán)境,是一個(gè)非常不錯(cuò)的選擇。至于Whidbey時(shí)代的Visual C++,
似乎微軟所最關(guān)注的是C++/CLI……我們不想評(píng)論微軟下一代的C++編譯器對(duì)標(biāo)準(zhǔn)化
兼容如何,但他確實(shí)越來(lái)越適合.NET (其實(shí)你和我的感覺(jué)可能是一樣的,微軟不應(yīng)
當(dāng)把標(biāo)準(zhǔn)C++這塊肥肉丟給Borland,然而微軟可能并不這樣認(rèn)為)。
2.3 GNU C++
著名的開(kāi)源C++編譯器。是類Unix操作系統(tǒng)下編寫C++程序的首選。特點(diǎn)是有非
常好的移植性,你可以在非常廣泛的平臺(tái)上使用它,同時(shí)也是編寫跨平臺(tái),嵌入式
程序很好的選擇。另外在符合標(biāo)準(zhǔn)這個(gè)方面一直都非常好,GCC3.3大概能夠達(dá)到96
.15%。但是由于其跨平臺(tái)的特性,在代碼尺寸速度等優(yōu)化上略微差一點(diǎn)。
基于GNU C++的編譯器有很多,比如:
(1) Mingw
http://www.mingw.org/
GCC的一個(gè)Windows的移植版本(Dev-C++的后臺(tái))
(2) Cygwin
http://sources.redhat.com/cygwin/
GCC的另外一個(gè)Windows移植版本是Cygwin的一部分,Cygwin是Windows下的一個(gè)
Unix仿真環(huán)境。嚴(yán)格的說(shuō)是模擬GNU的環(huán)境,這也就是"Gnu's Not Unix"要表達(dá)的意
思,噢,扯遠(yuǎn)了,這并不是我們?cè)谶@里關(guān)心的實(shí)質(zhì)內(nèi)容。
(3) Djgpp
http://www.delorie.com/djgpp/
這是GCC的DOS移植版本。
(4) RSXNT
http://www.mathematik.uni-bielefeld.de/~rainer/
這是GCC的DOS和Windows移植版本。
(5) Intel C++
著名CPU制造廠商Intel出品的編譯器,Special Design for Intel x86!對(duì)于
Intel x86結(jié)構(gòu)的CPU經(jīng)過(guò)特別的優(yōu)化。在有些應(yīng)用情況下,特別是數(shù)值計(jì)算等高性
能應(yīng)用,僅僅采用Intel的編譯器編譯就能大幅度的提高性能。
(6) Digital Mars C++
網(wǎng)絡(luò)上提供免費(fèi)下載,Zortech/Symantec C++的繼承者,其前身在當(dāng)年慘烈的
C++四國(guó)戰(zhàn)中也是主角之一。
------------------------------------------------------------------------
--------
3,開(kāi)發(fā)環(huán)境
開(kāi)發(fā)環(huán)境對(duì)于程序員的作用不言而喻。選擇自己朝夕相處的環(huán)境也不是容易的
事情,特別是在IDE如此豐富的情況下。下面就是我們推薦的一些常見(jiàn)的C++開(kāi)發(fā)環(huán)
境,并沒(méi)有包括一些小型的,罕見(jiàn)的IDE。其中任何一款都是功能豐富,可以用作日
常開(kāi)發(fā)使用的。對(duì)于不同層面的開(kāi)發(fā)者,請(qǐng)參見(jiàn)內(nèi)文關(guān)于適用對(duì)象的描述。
3.1 Visual Studio 6.0
這個(gè)雖然是Microsoft公司的老版本的開(kāi)發(fā)環(huán)境,但是鑒于其后繼版本Visual
Studio.NET的龐大身軀,以及初學(xué)者并不那么高的功能要求,所以推薦這個(gè)開(kāi)發(fā)環(huán)
境給C++的初學(xué)者,供其學(xué)習(xí)C++的最基本的部分,比如C的那部分子集,當(dāng)然你別指
望他能夠支持最新的C99標(biāo)準(zhǔn)。在日常的開(kāi)發(fā)中,仍然有很多公司使用這個(gè)經(jīng)典穩(wěn)定
的環(huán)境,比如筆者就看曾親見(jiàn)有些公司將其編譯器替換為GCC做手機(jī)開(kāi)發(fā)之用。
3.2 Visual Studio.NET 2003
作為Microsoft公司官方正式發(fā)布的最新版本開(kāi)發(fā)環(huán)境,其中有太多激動(dòng)人心的
功能。結(jié)合其最新的C++編譯器。對(duì)于機(jī)器配置比較好的開(kāi)發(fā)人員來(lái)說(shuō),使用這個(gè)開(kāi)
發(fā)環(huán)境將能滿足其大部分的要求。這里不打算單獨(dú)說(shuō)Visual Studio Whidbey,雖然
Visual Studio .NET 2005 - Whidbey社區(qū)預(yù)覽版已經(jīng)推出,但暫不是很穩(wěn)定,讀者
可以親身去體驗(yàn)。
3.3 Borland C++ Builder 6
這個(gè)并不是Borland的C++開(kāi)發(fā)環(huán)境的最新版本。選擇它的原因是它不是用Java
寫的IDE,速度比較快。它有一個(gè)很完善的GUI窗體設(shè)計(jì)器,和Delphi共用一個(gè)VCL。
由于這些特點(diǎn),比較適合初學(xué)者上手。但是由于其GUI的中心位置,可能不利于對(duì)于
C++語(yǔ)言的學(xué)習(xí)。而且其為了支持VCL這個(gè)Object Pascal寫的庫(kù)也對(duì)C++進(jìn)行了一些
私有的擴(kuò)充。使得人們有一個(gè)不得不接受的事實(shí):“Borland C++ Builder 6的高手
幾乎都是Delphi高手”。
3.4 Borland C++ Builder X
正如前文所述,雖然版本號(hào)上和前面那個(gè)IDE非常相象,但是其實(shí)它們是完全不
同的兩個(gè)集成開(kāi)發(fā)環(huán)境。C++Builder更多的是一個(gè)和Delphi同步的C++版本的開(kāi)發(fā)環(huán)
境,C++BuilderX則是完全從C++的角度思考得出的一個(gè)功能豐富的IDE。其最大的特
點(diǎn)是跨平臺(tái),跨編譯器,多種Framework的集成,并且有一個(gè)WxWindows為基礎(chǔ)的GU
I設(shè)計(jì)器。尤其是采用了純C++來(lái)重寫了整個(gè)Framework,摒棄了以前令人無(wú)奈的版本
。對(duì)于C++的開(kāi)發(fā)來(lái)說(shuō),從編譯器,到庫(kù),到功能集成都是非常理想的。可以預(yù)見(jiàn),
Borland C++ Builder X 2.0很值得C++愛(ài)好者期待。唯一令人難堪之處是作為一個(gè)
C++的開(kāi)發(fā)工具,其IDE是用Java寫的,在配置不夠理想的機(jī)器上請(qǐng)慎重考慮再安裝
。
3.5 Emacs + GCC
前面講的大部分是Windows環(huán)境下的集成開(kāi)發(fā)環(huán)境。Linux上的開(kāi)發(fā)者更傾向于
使用Emacs來(lái)編輯C++的文件,用Makefile來(lái)命令GCC做編譯。雖然看上去比較松散,
但是這些東西綜合起來(lái)還是一個(gè)開(kāi)0發(fā)環(huán)境。如果你能夠嫻熟的使用這樣的環(huán)境寫程
序,你的水平應(yīng)該足夠指導(dǎo)我們來(lái)寫這篇陋文了。
3.6 Dev C++
GCC是一個(gè)很好的編譯器。在Windows上的C++編譯器一直和標(biāo)準(zhǔn)有著一段距離的
時(shí)候,GCC就是一個(gè)讓W(xué)indows下開(kāi)發(fā)者流口水的編譯器。Dev-C++就是能夠讓GCC跑
在Windows下的工具,作為集成開(kāi)發(fā)環(huán)境,還提供了同專業(yè)IDE相媲美的語(yǔ)法高亮,
代碼提示,調(diào)試等功能。由于使用Delphi開(kāi)發(fā),占用內(nèi)存少,速度很快,比較適合
輕量級(jí)的學(xué)習(xí)和使用。
3.7 Eclipse + CDT
Eclipse可是近來(lái)大名鼎鼎的開(kāi)發(fā)工具。最新一期的Jolt大獎(jiǎng)就頒給了這個(gè)杰出
的神物。說(shuō)其神奇是因?yàn)椋旧硎怯肑ava寫的,但是擁有比一般Java寫的程序快
得多的速度。而且因?yàn)槠浠诓寮M裝一切的原則,使得能夠有CDT這樣的插件把E
clipse變成一個(gè)C/C++的開(kāi)發(fā)環(huán)境。如果你一直用Eclipse寫Java的程序,不妨用它
體驗(yàn)一下C++開(kāi)發(fā)的樂(lè)趣。
------------------------------------------------------------------------
--------
4,工具
C++的輔助工具繁多,我們分門別類的為大家作介紹:
4.1 文檔類
(1) Doxygen
參考站點(diǎn):http://www.doxygen.org
Doxygen是一種適合C風(fēng)格語(yǔ)言(如C++、C、IDL、Java甚至包括C#和PHP)的、
開(kāi)放源碼的、基于命令行的文檔產(chǎn)生器。
(2) C++2HTML
參考站點(diǎn):http://www.bedaux.net/cpp2html/
把C++代碼變成語(yǔ)法高亮的HTML
(3) CodeColorizer
參考站點(diǎn):http://www.chami.com/colorizer/
它能把好幾種語(yǔ)言的源代碼著色為HTML
(4) Doc-O-Matic
參考站點(diǎn):http://www.doc-o-matic.com/
Doc-O_Matic為你的C/C++,C++.net,Delphi/Pascal, VB.NET,C#和Java程序
或者組件產(chǎn)生準(zhǔn)確的文檔。Doc-O-Matic使用源代碼中的符號(hào)和注釋以及外部的文檔
文件創(chuàng)建與流行的文檔樣式一致的文檔。
(5) DocVizor
參考站點(diǎn):http://www.ucancode.net/Products/DocBuilder/Features.htm
DocVizor滿足了面向?qū)ο筌浖_(kāi)發(fā)者的基本要求——它讓我們能夠看到C++工程
中的類層次結(jié)構(gòu)。DocVizor快速地產(chǎn)生完整可供打印的類層次結(jié)構(gòu)圖,包括從第三
方庫(kù)中來(lái)的那些類,除此之外DocVizor還能從類信息中產(chǎn)生HTML文件。
(6) SourcePublisher C++
參考站點(diǎn):http://www.scitools.com/sourcepublisher_c.html
給源代碼產(chǎn)生提供快速直觀的HTML報(bào)表,包括代碼,類層次結(jié)構(gòu),調(diào)用和被調(diào)
用樹(shù),包含和被包含樹(shù)。支持多種操作系統(tǒng)。
(7) Understand
參考站點(diǎn):http://www.scitools.com/ucpp.html
分析任何規(guī)模的C或者C++工程,幫助我們更好的理解以及編寫文檔。
4.2 代碼類
(1) CC-Rider
參考站點(diǎn):http://www.cc-rider.com
CC-Rider是用于C/C++程序強(qiáng)大的代碼可視化工具,通過(guò)交互式瀏覽、編輯及自
動(dòng)文件來(lái)促進(jìn)程序的維持和發(fā)展。
(2) CodeInspect
參考站點(diǎn):http://www.yokasoft.com/
一種新的C/C++代碼分析工具。它檢查我們的源代碼找出非標(biāo)準(zhǔn)的,可能的,以
及普通的錯(cuò)誤代碼。
(3) CodeWizard
參考站點(diǎn):http://www.parasoft.com
先進(jìn)的C/C++源代碼分析工具,使用超過(guò)500個(gè)編碼規(guī)范自動(dòng)化地標(biāo)明危險(xiǎn)的,
但是編譯器不能檢查到的代碼結(jié)構(gòu)。
(4) C++ Validation Test Suites
參考站點(diǎn):http://www.plumhall.com/suites.html
一組用于測(cè)試編譯器和庫(kù)對(duì)于標(biāo)準(zhǔn)吻合程度的代碼庫(kù)。
(5) CppRefactory
參考站點(diǎn):http://cpptool.sourceforge.net/
CPPRefactory是一個(gè)使得開(kāi)發(fā)者能夠重構(gòu)他們的C++代碼的程序。目的是使得C
++代碼的重構(gòu)能夠盡可能的有效率和簡(jiǎn)單。
(6) Lzz
參考站點(diǎn):http://www.lazycplusplus.com/
Lzz是一個(gè)自動(dòng)化許多C++編程中的體力活的工具。它能夠節(jié)省我們?cè)S多事件并
且使得編碼更加有樂(lè)趣。給出一系列的聲明,Lzz會(huì)給我們創(chuàng)建頭文件和源文件。
(7) QA C++ Generation 2000
參考站點(diǎn):http://www.programmingresearch.com/solutions/qacpp.htm
它關(guān)注面向?qū)ο蟮腃++源代碼,對(duì)有關(guān)于設(shè)計(jì),效率,可靠性,可維護(hù)性的部分
提出警告信息。
(8) s-mail project - Java to C++DOL
參考站點(diǎn):http://sadlocha.strefa.pl/s-mail/ja2dol.html
把Java源代碼翻譯為相應(yīng)的C++源代碼的命令行工具。
(9) SNIP from Cleanscape Software International
參考站點(diǎn):http://www.cleanscape.net/stdprod/snip/index.html
一個(gè)填平編碼和設(shè)計(jì)之間溝壑的易于使用的C++開(kāi)發(fā)工具,節(jié)省大量編輯和調(diào)試
的事件,它還使得開(kāi)發(fā)者能夠指定設(shè)計(jì)模式作為對(duì)象模型,自動(dòng)從對(duì)象模型中產(chǎn)生
C++的類。
(10) SourceStyler C++
參考站點(diǎn):http://www.ochresoftware.com/
對(duì)C/C++源代碼提供完整的格式化和排版控制的工具。提供多于75個(gè)的格式化選
項(xiàng)以及完全支持ANSI C++。
4.3 編譯類
(1) Compilercache
參考站點(diǎn):http://www.erikyyy.de/compilercache/
Compilercache是一個(gè)對(duì)你的C和C++編譯器的封裝腳本。每次我們進(jìn)行編譯,封
裝腳本,把編譯的結(jié)果放入緩存,一旦編譯相同的東西,結(jié)果將從緩存中取出而不
是再次編譯。
(2) Ccache
參考站點(diǎn):http://ccache.samba.org/
Ccache是一個(gè)編譯器緩存。它使用起來(lái)就像C/C++編譯器的緩存預(yù)處理器,編譯
速度通常能提高普通編譯過(guò)程的5~10倍。
(3) Cmm (C++ with MultiMethods)
參考站點(diǎn):http://www.op59.net/cmm/cmm-0.28/users.html
這是一種C++語(yǔ)言的擴(kuò)展。讀入Cmm源代碼輸出C++的源代碼,功能是對(duì)C++語(yǔ)言
添加了對(duì)multimethod的支持。
(4) The Frost Project
參考站點(diǎn):http://frost.flewid.de/
Forst使得你能夠在C++程序中像原生的C++特性一樣使用multimethod以及虛函
數(shù)參數(shù)。它是一個(gè)編譯器的外殼。
4.4 測(cè)試和調(diào)試類
(1) CPPUnit
CppUnit 是個(gè)基于 LGPL 的開(kāi)源項(xiàng)目,最初版本移植自 JUnit,是一個(gè)非常優(yōu)
秀的開(kāi)源測(cè)試框架。CppUnit 和 JUnit 一樣主要思想來(lái)源于極限編程。主要功能就
是對(duì)單元測(cè)試進(jìn)行管理,并可進(jìn)行自動(dòng)化測(cè)試。
(2) C++Test
參考站點(diǎn):http://www.parasoft.com/
C++ Test是一個(gè)單元測(cè)試工具,它自動(dòng)化了C和C++類,函數(shù)或者組件的測(cè)試。
(3) Cantata++
參考站點(diǎn):http://www.iplbath.com/products/tools/pt400.shtml
設(shè)計(jì)的目的是為了滿足在合理的經(jīng)濟(jì)開(kāi)銷下使用這個(gè)工具可以讓開(kāi)發(fā)工程師開(kāi)
展單元測(cè)試和集成測(cè)試的需求.
(4) Purify
參考站點(diǎn):http://www-900.ibm.com/cn/software/rational/products/purif
yplus/index.shtml
IBM Rational PurifyPlus是一套完整的運(yùn)行時(shí)分析工具,旨在提高應(yīng)用程序的
可靠性和性能。PurifyPlus將內(nèi)存錯(cuò)誤和泄漏檢測(cè)、應(yīng)用程序性能描述、代碼覆蓋
分析等功能組合在一個(gè)單一、完整的工具包中。
(5) BoundsChecker
BoundsChecker是一個(gè)C++運(yùn)行時(shí)錯(cuò)誤檢測(cè)和調(diào)試工具。它通過(guò)在Visual Studi
o內(nèi)自動(dòng)化調(diào)試過(guò)程加速開(kāi)發(fā)并且縮短上市的周期。BoundsChecker提供清楚,詳細(xì)
的程序錯(cuò)誤分析,許多是對(duì)C++獨(dú)有的并且在static,stack和heap內(nèi)存中檢測(cè)和診
斷錯(cuò)誤,以及發(fā)現(xiàn)內(nèi)存和資源的泄漏。 (6) Insure++
參考站點(diǎn):http://www.parasoft.com/
一個(gè)自動(dòng)化的運(yùn)行時(shí)程序測(cè)試工具,檢查難以察覺(jué)的錯(cuò)誤,如內(nèi)存覆蓋,內(nèi)存泄
漏,內(nèi)存分配錯(cuò)誤,變量初始化錯(cuò)誤,變量定義沖突,指針錯(cuò)誤,庫(kù)錯(cuò)誤,邏輯錯(cuò)
誤和算法錯(cuò)誤等。
(7) GlowCode
參考站點(diǎn):http://www.glowcode.com/
GlowCode包括內(nèi)存泄漏檢查,code profiler,函數(shù)調(diào)用跟蹤等功能。給C++開(kāi)
發(fā)者提供完整的錯(cuò)誤診斷,和運(yùn)行時(shí)性能分析工具包。
(8) Stack Spy
參考站點(diǎn):http://www.imperioustech.com/
它能捕捉stack corruption, stack over run, stack overflow等有關(guān)棧的錯(cuò)
誤。
------------------------------------------------------------------------
--------
5,庫(kù)
在C++中,庫(kù)的地位是非常高的。C++之父 Bjarne Stroustrup先生多次表示了
設(shè)計(jì)庫(kù)來(lái)擴(kuò)充功能要好過(guò)設(shè)計(jì)更多的語(yǔ)法的言論。現(xiàn)實(shí)中,C++的庫(kù)門類繁多,解決
的問(wèn)題也是極其廣泛,庫(kù)從輕量級(jí)到重量級(jí)的都有。不少都是讓人眼界大開(kāi),亦或
是望而生嘆的思維杰作。由于庫(kù)的數(shù)量非常龐大,而且限于筆者水平,其中很多并
不了解。所以文中所提的一些庫(kù)都是比較著名的大型庫(kù)。
5.1 標(biāo)準(zhǔn)庫(kù)
標(biāo)準(zhǔn)庫(kù)中提供了C++程序的基本設(shè)施。雖然C++標(biāo)準(zhǔn)庫(kù)隨著C++標(biāo)準(zhǔn)折騰了許多年
,直到標(biāo)準(zhǔn)的出臺(tái)才正式定型,但是在標(biāo)準(zhǔn)庫(kù)的實(shí)現(xiàn)上卻很令人欣慰得看到多種實(shí)
現(xiàn),并且已被實(shí)踐證明為有工業(yè)級(jí)別強(qiáng)度的佳作。
(1) Dinkumware C++ Library
參考站點(diǎn):http://www.dinkumware.com/
P.J. Plauger編寫的高品質(zhì)的標(biāo)準(zhǔn)庫(kù)。P.J. Plauger博士是Dr. Dobb's程序設(shè)
計(jì)杰出獎(jiǎng)的獲得者。其編寫的庫(kù)長(zhǎng)期被Microsoft采用,并且最近Borland也取得了
其OEM的license,在其C/C++的產(chǎn)品中采用Dinkumware的庫(kù)。
(2) RogueWave Standard C++ Library
參考站點(diǎn):http://www.roguewave.com/
這個(gè)庫(kù)在Borland C++ Builder的早期版本中曾經(jīng)被采用,后來(lái)被其他的庫(kù)給替
換了。筆者不推薦使用。
(3) SGI STL
參考站點(diǎn):http://www.roguewave.com/
SGI公司的C++標(biāo)準(zhǔn)模版庫(kù)。
(4) STLport
參考站點(diǎn):http://www.stlport.org/
SGI STL庫(kù)的跨平臺(tái)可移植版本。
5.2 “準(zhǔn)”標(biāo)準(zhǔn)庫(kù) - Boost
參考站點(diǎn):http://www.boost.org
國(guó)內(nèi)鏡像:http://www.c-view.org/tech/lib/boost/index.htm
Boost庫(kù)是一個(gè)經(jīng)過(guò)千錘百煉、可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后
備,是C++標(biāo)準(zhǔn)化進(jìn)程的發(fā)動(dòng)機(jī)之一。 Boost庫(kù)由C++標(biāo)準(zhǔn)委員會(huì)庫(kù)工作組成員發(fā)起
,在C++社區(qū)中影響甚大,其成員已近2000人。 Boost庫(kù)為我們帶來(lái)了最新、最酷、
最實(shí)用的技術(shù),是不折不扣的“準(zhǔn)”標(biāo)準(zhǔn)庫(kù)。
Boost中比較有名氣的有這么幾個(gè)庫(kù):
Regex
正則表達(dá)式庫(kù)
Spirit
LL parser framework,用C++代碼直接表達(dá)EBNF
Graph
圖組件和算法
Lambda
在調(diào)用的地方定義短小匿名的函數(shù)對(duì)象,很實(shí)用的functional功能
concept check
檢查泛型編程中的concept
Mpl
用模板實(shí)現(xiàn)的元編程框架
Thread
可移植的C++多線程庫(kù)
Python
把C++類和函數(shù)映射到Python之中
Pool
內(nèi)存池管理
smart_ptr
5個(gè)智能指針,學(xué)習(xí)智能指針必讀,一份不錯(cuò)的參考是來(lái)自CUJ的文章:
Smart Pointers in Boost,哦,這篇文章可以查到,CUJ是提供在線瀏覽的。
中文版見(jiàn)筆者在《Dr. Dobb's Journal軟件研發(fā)雜志》第7輯上的譯文。
Boost總體來(lái)說(shuō)是實(shí)用價(jià)值很高,質(zhì)量很高的庫(kù)。并且由于其對(duì)跨平臺(tái)的強(qiáng)調(diào),
對(duì)標(biāo)準(zhǔn)C++的強(qiáng)調(diào),是編寫平臺(tái)無(wú)關(guān),現(xiàn)代C++的開(kāi)發(fā)者必備的工具。但是Boost中也
有很多是實(shí)驗(yàn)性質(zhì)的東西,在實(shí)際的開(kāi)發(fā)中實(shí)用需要謹(jǐn)慎。并且很多Boost中的庫(kù)功
能堪稱對(duì)語(yǔ)言功能的擴(kuò)展,其構(gòu)造用盡精巧的手法,不要貿(mào)然的花費(fèi)時(shí)間研讀。Bo
ost另外一面,比如Graph這樣的庫(kù)則是具有工業(yè)強(qiáng)度,結(jié)構(gòu)良好,非常值得研讀的
精品代碼,并且也可以放心的在產(chǎn)品代碼中多多利用。
5.3 GUI
在眾多C++的庫(kù)中,GUI部分的庫(kù)算是比較繁榮,也比較引人注目的。在實(shí)際開(kāi)
發(fā)中,GUI庫(kù)的選擇也是非常重要的一件事情,下面我們綜述一下可選擇的GUI庫(kù),
各自的特點(diǎn)以及相關(guān)工具的支持。
(1) MFC
大名鼎鼎的微軟基礎(chǔ)類庫(kù)(Microsoft Foundation Class)。大凡學(xué)過(guò)VC++的
人都應(yīng)該知道這個(gè)庫(kù)。雖然從技術(shù)角度講,MFC是不大漂亮的,但是它構(gòu)建于Windo
ws API 之上,能夠使程序員的工作更容易,編程效率高,減少了大量在建立 Windo
ws 程序時(shí)必須編寫的代碼,同時(shí)它還提供了所有一般 C++ 編程的優(yōu)點(diǎn),例如繼承
和封裝。MFC 編寫的程序在各個(gè)版本的Windows操作系統(tǒng)上是可移植的,例如,在
Windows 3.1下編寫的代碼可以很容易地移植到 Windows NT 或 Windows 95 上。但
是在最近發(fā)展以及官方支持上日漸勢(shì)微。
(2) QT
參考網(wǎng)站:http://www.trolltech.com/
Qt是Trolltech公司的一個(gè)多平臺(tái)的C++圖形用戶界面應(yīng)用程序框架。它提供給
應(yīng)用程序開(kāi)發(fā)者建立藝術(shù)級(jí)的圖形用戶界面所需的所用功能。Qt是完全面向?qū)ο蟮?br>很容易擴(kuò)展,并且允許真正地組件編程。自從1996年早些時(shí)候,Qt進(jìn)入商業(yè)領(lǐng)域,
它已經(jīng)成為全世界范圍內(nèi)數(shù)千種成功的應(yīng)用程序的基礎(chǔ)。Qt也是流行的Linux桌面環(huán)
境KDE 的基礎(chǔ),同時(shí)它還支持Windows、Macintosh、Unix/X11等多種平臺(tái)。
(3) WxWindows
參考網(wǎng)站:http://www.wxwindows.org/
跨平臺(tái)的GUI庫(kù)。因?yàn)槠漕悓哟螛O像MFC,所以有文章介紹從MFC到WxWindows的
代碼移植以實(shí)現(xiàn)跨平臺(tái)的功能。通過(guò)多年的開(kāi)發(fā)也是一個(gè)日趨完善的GUI庫(kù),支持同
樣不弱于前面兩個(gè)庫(kù)。并且是完全開(kāi)放源代碼的。新近的C++ Builder X的GUI設(shè)計(jì)
器就是基于這個(gè)庫(kù)的。
(4) Fox
參考網(wǎng)站:http://www.fox-toolkit.org/
開(kāi)放源代碼的GUI庫(kù)。作者從自己親身的開(kāi)發(fā)經(jīng)驗(yàn)中得出了一個(gè)理想的GUI庫(kù)應(yīng)
該是什么樣子的感受出發(fā),從而開(kāi)始了對(duì)這個(gè)庫(kù)的開(kāi)發(fā)。有興趣的可以嘗試一下。
(5) WTL
基于ATL的一個(gè)庫(kù)。因?yàn)槭褂昧舜罅緼TL的輕量級(jí)手法,模板等技術(shù),在代碼尺
寸,以及速度優(yōu)化方面做得非常到位。主要面向的使用群體是開(kāi)發(fā)COM輕量級(jí)供網(wǎng)絡(luò)
下載的可視化控件的開(kāi)發(fā)者。
(6) GTK
參考網(wǎng)站:http://gtkmm.sourceforge.net/
GTK是一個(gè)大名鼎鼎的C的開(kāi)源GUI庫(kù)。在Linux世界中有Gnome這樣的殺手應(yīng)用。
而GTK就是這個(gè)庫(kù)的C++封裝版本。
5.4 網(wǎng)絡(luò)通信
(1) ACE
參考網(wǎng)站:http://www.cs.wustl.edu/~schmidt/ACE.html
C++庫(kù)的代表,超重量級(jí)的網(wǎng)絡(luò)通信開(kāi)發(fā)框架。ACE自適配通信環(huán)境(Adaptive
Communication Environment)是可以自由使用、開(kāi)放源代碼的面向?qū)ο罂蚣埽?br>其中實(shí)現(xiàn)了許多用于并發(fā)通信軟件的核心模式。ACE提供了一組豐富的可復(fù)用C++包
裝外觀(Wrapper Facade)和框架組件,可跨越多種平臺(tái)完成通用的通信軟件任務(wù)
,其中包括:事件多路分離和事件處理器分派、信號(hào)處理、服務(wù)初始化、進(jìn)程間通
信、共享內(nèi)存管理、消息路由、分布式服務(wù)動(dòng)態(tài)(重)配置、并發(fā)執(zhí)行和同步,等
等。
(2) StreamModule
參考網(wǎng)站:http://www.omnifarious.org/StrMod/
設(shè)計(jì)用于簡(jiǎn)化編寫分布式程序的庫(kù)。嘗試著使得編寫處理異步行為的程序更容
易,而不是用同步的外殼包起異步的本質(zhì)。
(3) SimpleSocket
參考網(wǎng)站:http://home.hetnet.nl/~lcbokkers/simsock.htm
這個(gè)類庫(kù)讓編寫基于socket的客戶/服務(wù)器程序更加容易。
(4) A Stream Socket API for C++
參考網(wǎng)站:http://www.pcs.cnu.edu/~dgame/sockets/socketsC++/sockets.h
tml
又一個(gè)對(duì)Socket的封裝庫(kù)。
5.5 XML
(1) Xerces
參考網(wǎng)站:http://xml.apache.org/xerces-c/
Xerces-C++ 是一個(gè)非常健壯的XML解析器,它提供了驗(yàn)證,以及SAX和DOM API
。XML驗(yàn)證在文檔類型定義(Document Type Definition,DTD)方面有很好的支持,
并且在2001年12月增加了支持W3C XML Schema 的基本完整的開(kāi)放標(biāo)準(zhǔn)。
(2) XMLBooster
參考網(wǎng)站:http://www.xmlbooster.com/
這個(gè)庫(kù)通過(guò)產(chǎn)生特制的parser的辦法極大的提高了XML解析的速度,并且能夠產(chǎn)
生相應(yīng)的GUI程序來(lái)修改這個(gè)parser。在DOM和SAX兩大主流XML解析辦法之外提供了
另外一個(gè)可行的解決方案。
(3) Pull Parser
參考網(wǎng)站:http://www.extreme.indiana.edu/xgws/xsoap/xpp/
這個(gè)庫(kù)采用pull方法的parser。在每個(gè)SAX的parser底層都有一個(gè)pull的parse
r,這個(gè)xpp把這層暴露出來(lái)直接給大家使用。在要充分考慮速度的時(shí)候值得嘗試。
(4) Xalan
參考網(wǎng)站:http://xml.apache.org/xalan-c/
Xalan是一個(gè)用于把XML文檔轉(zhuǎn)換為HTML,純文本或者其他XML類型文檔的XSLT處
理器。
(5) CMarkup
參考網(wǎng)站:http://www.firstobject.com/xml.htm
這是一種使用EDOM的XML解析器。在很多思路上面非常靈活實(shí)用。值得大家在D
OM和SAX之外尋求一點(diǎn)靈感。
(6) libxml++
http://libxmlplusplus.sourceforge.net/
libxml++是對(duì)著名的libxml XML解析器的C++封裝版本
5.6 科學(xué)計(jì)算
(1) Blitz++
參考網(wǎng)站:http://www.oonumerics.org/blitz/
Blitz++ 是一個(gè)高效率的數(shù)值計(jì)算函數(shù)庫(kù),它的設(shè)計(jì)目的是希望建立一套既具
像C++ 一樣方便,同時(shí)又比Fortran速度更快的數(shù)值計(jì)算環(huán)境。通常,用C++所寫出
的數(shù)值程序,比 Fortran慢20%左右,因此Blitz++正是要改掉這個(gè)缺點(diǎn)。方法是利
用C++的template技術(shù),程序執(zhí)行甚至可以比Fortran更快。Blitz++目前仍在發(fā)展中
,對(duì)于常見(jiàn)的SVD,F(xiàn)FTs,QMRES等常見(jiàn)的線性代數(shù)方法并不提供,不過(guò)使用者可以
很容易地利用Blitz++所提供的函數(shù)來(lái)構(gòu)建。
(2) POOMA
參考網(wǎng)站:http://www.codesourcery.com/pooma/pooma
POOMA是一個(gè)免費(fèi)的高性能的C++庫(kù),用于處理并行式科學(xué)計(jì)算。POOMA的面向?qū)?br>象設(shè)計(jì)方便了快速的程序開(kāi)發(fā),對(duì)并行機(jī)器進(jìn)行了優(yōu)化以達(dá)到最高的效率,方便在
工業(yè)和研究環(huán)境中使用。
(3) MTL
參考網(wǎng)站:http://www.osl.iu.edu/research/mtl/
Matrix Template Library(MTL)是一個(gè)高性能的泛型組件庫(kù),提供了各種格式
矩陣的大量線性代數(shù)方面的功能。在某些應(yīng)用使用高性能編譯器的情況下,比如In
tel的編譯器,從產(chǎn)生的匯編代碼可以看出其與手寫幾乎沒(méi)有兩樣的效能。
(4) CGAL
參考網(wǎng)站:www.cgal.org
Computational Geometry Algorithms Library的目的是把在計(jì)算幾何方面的大
部分重要的解決方案和方法以C++庫(kù)的形式提供給工業(yè)和學(xué)術(shù)界的用戶。
5.7 游戲開(kāi)發(fā)
(1) Audio/Video 3D C++ Programming Library
參考網(wǎng)站:http://www.galacticasoftware.com/products/av/
***3D是一個(gè)跨平臺(tái),高性能的C++庫(kù)。主要的特性是提供3D圖形,聲效支持(S
B,以及S3M),控制接口(鍵盤,鼠標(biāo)和遙感),XMS。
(2) KlayGE
參考網(wǎng)站:http://home.g365.net/enginedev/
國(guó)內(nèi)游戲開(kāi)發(fā)高手自己用C++開(kāi)發(fā)的游戲引擎。KlayGE是一個(gè)開(kāi)放源代碼、跨平
臺(tái)的游戲引擎,并使用Python作腳本語(yǔ)言。KlayGE在LGPL協(xié)議下發(fā)行。感謝龔敏敏
先生為中國(guó)游戲開(kāi)發(fā)事業(yè)所做出的貢獻(xiàn)。
(3) OGRE
參考網(wǎng)站:http://www.ogre3d.org
OGRE(面向?qū)ο蟮膱D形渲染引擎)是用C++開(kāi)發(fā)的,使用靈活的面向?qū)ο?D引擎
。它的目的是讓開(kāi)發(fā)者能更方便和直接地開(kāi)發(fā)基于3D硬件設(shè)備的應(yīng)用程序或游戲。
引擎中的類庫(kù)對(duì)更底層的系統(tǒng)庫(kù)(如:Direct3D和OpenGL)的全部使用細(xì)節(jié)進(jìn)行了
抽象,并提供了基于現(xiàn)實(shí)世界對(duì)象的接口和其它類。
5.8 線程
(1) C++ Threads
參考網(wǎng)站:http://threads.sourceforge.net/
這個(gè)庫(kù)的目標(biāo)是給程序員提供易于使用的類,這些類被繼承以提供在Linux環(huán)境
中很難看到的大量的線程方面的功能。
(2) ZThreads
參考網(wǎng)站:http://zthread.sourceforge.net/
一個(gè)先進(jìn)的面向?qū)ο螅缙脚_(tái)的C++線程和同步庫(kù)。
5.9 序列化
(1) s11n
參考網(wǎng)站:http://s11n.net/
一個(gè)基于STL的C++庫(kù),用于序列化POD,STL容器以及用戶定義的類型。
(2) Simple XML Persistence Library
參考網(wǎng)站:http://sxp.sourceforge.net/
這是一個(gè)把對(duì)象序列化為XML的輕量級(jí)的C++庫(kù)。
5.10 字符串
(1) C++ Str Library
參考網(wǎng)站:http://www.utilitycode.com/str/
操作字符串和字符的庫(kù),支持Windows和支持gcc的多種平臺(tái)。提供高度優(yōu)化的
代碼,并且支持多線程環(huán)境和Unicode,同時(shí)還有正則表達(dá)式的支持。
(2) Common Text Transformation Library
參考網(wǎng)站:http://cttl.sourceforge.net/
這是一個(gè)解析和修改STL字符串的庫(kù)。CTTL substring類可以用來(lái)比較,插入,
替換以及用EBNF的語(yǔ)法進(jìn)行解析。
(3) GRETA
參考網(wǎng)站:http://research.microsoft.com/projects/greta/
這是由微軟研究院的研究人員開(kāi)發(fā)的處理正則表達(dá)式的庫(kù)。在小型匹配的情況
下有非常優(yōu)秀的表現(xiàn)。
5.11 綜合
(1) P::Classes
參考網(wǎng)站:http://pclasses.com/
一個(gè)高度可移植的C++應(yīng)用程序框架。當(dāng)前關(guān)注類型和線程安全的signal/slot
機(jī)制,i/o系統(tǒng)包括基于插件的網(wǎng)絡(luò)協(xié)議透明的i/o架構(gòu),基于插件的應(yīng)用程序消息
日志框架,訪問(wèn)sql數(shù)據(jù)庫(kù)的類等等。
(2) ACDK - Artefaktur Component Development Kit
參考網(wǎng)站:http://acdk.sourceforge.net/
這是一個(gè)平臺(tái)無(wú)關(guān)的C++組件框架,類似于Java或者.NET中的框架(反射機(jī)制,
線程,Unicode,廢料收集,I/O,網(wǎng)絡(luò),實(shí)用工具,XML,等等),以及對(duì)Java, P
erl, Python, TCL, Lisp, COM 和 CORBA的集成。
(3) dlib C++ library
參考網(wǎng)站:http://www.cis.ohio-state.edu/~kingd/dlib/
各種各樣的類的一個(gè)綜合。大整數(shù),Socket,線程,GUI,容器類,以及瀏覽目
錄的API等等。
(4) Chilkat C++ Libraries
參考網(wǎng)站:http://www.chilkatsoft.com/cpp_libraries.asp
這是提供zip,e-mail,編碼,S/MIME,XML等方面的庫(kù)。
(5) C++ Portable Types Library (PTypes)
參考網(wǎng)站:http://www.melikyan.com/ptypes/
這是STL的比較簡(jiǎn)單的替代品,以及可移植的多線程和網(wǎng)絡(luò)庫(kù)。
(6) LFC
參考網(wǎng)站:http://lfc.sourceforge.net/
哦,這又是一個(gè)嘗試提供一切的C++庫(kù)
5.12 其他庫(kù)
(1) Loki
參考網(wǎng)站:http://www.moderncppdesign.com/
哦,你可能抱怨我早該和Boost一起介紹它,一個(gè)實(shí)驗(yàn)性質(zhì)的庫(kù)。作者在loki中
把C++模板的功能發(fā)揮到了極致。并且嘗試把類似設(shè)計(jì)模式這樣思想層面的東西通過(guò)
庫(kù)來(lái)提供。同時(shí)還提供了智能指針這樣比較實(shí)用的功能。
(2) ATL
ATL(Active Template Library)
是一組小巧、高效、靈活的類,這些類為創(chuàng)建可互操作的COM組件提供了基本的
設(shè)施。
(3) FC++: The Functional C++ Library
這個(gè)庫(kù)提供了一些函數(shù)式語(yǔ)言中才有的要素。屬于用庫(kù)來(lái)擴(kuò)充語(yǔ)言的一個(gè)代表
作。如果想要在OOP之外尋找另一分的樂(lè)趣,可以去看看函數(shù)式程序設(shè)計(jì)的世界。大
師Peter Norvig在 “Teach Yourself Programming in Ten Years”一文中就將函
數(shù)式語(yǔ)言列為至少應(yīng)當(dāng)學(xué)習(xí)的6類編程語(yǔ)言之一。
(4) FACT!
參考網(wǎng)站:http://www.kfa-juelich.de/zam/FACT/start/index.html
另外一個(gè)實(shí)現(xiàn)函數(shù)式語(yǔ)言特性的庫(kù)
(5) Crypto++
提供處理密碼,消息驗(yàn)證,單向hash,公匙加密系統(tǒng)等功能的免費(fèi)庫(kù)。
還有很多非常激動(dòng)人心或者是極其實(shí)用的C++庫(kù),限于我們的水平以及文章的篇
幅不能包括進(jìn)來(lái)。在對(duì)于這些已經(jīng)包含近來(lái)的庫(kù)的介紹中,由于并不是每一個(gè)我們
都使用過(guò),所以難免有偏頗之處,請(qǐng)讀者見(jiàn)諒。
------------------------------------------------------------------------
--------
6,書籍
以前熊節(jié)先生曾撰文評(píng)論相對(duì)于Java程序設(shè)計(jì)語(yǔ)言,C++的好書多如牛毛。榮耀
先生在《程序員》雜志上撰文《C++程序設(shè)計(jì)之四書五經(jīng)》也將本領(lǐng)域內(nèi)幾乎所有的
經(jīng)典書籍作了全面的介紹,任何關(guān)于書的評(píng)論此時(shí)看來(lái)便是很多余的了。個(gè)人淺見(jiàn),
除非你打算以C++作為唯一興趣或者生存之本,一般讀者確實(shí)沒(méi)有足夠的時(shí)間和必要
將20余本書籍全部閱讀。更有參考價(jià)值的是榮耀先生的另一篇文章:《至少應(yīng)該閱
讀的九本C++著作》,可以從下面的地址瀏覽到此文:
http://www.royaloo.com/articles/articles_2003/9CppBooks.htm
下面幾本書對(duì)于走在C++初學(xué)之路上的讀者是我們最愿意推薦給大家的:
(1) 《C++ Primer》
哦,也許你會(huì)抱怨我們?yōu)槭裁床幌冉榻BTCPL,但對(duì)于走在學(xué)習(xí)之路上的入門者,
本書內(nèi)容更為全面,更為詳細(xì)易懂,我們稱它為“C++的超級(jí)寶典”并不過(guò)分。配有
一本不錯(cuò)的習(xí)題解答《C++ Primer Answer Book》可以輔助你的學(xué)習(xí)之路。
(2) 《Essential C++》
如果說(shuō)《C++ Primer》是C++領(lǐng)域的超級(jí)寶典,那么此書作為掌握C++的大局觀
當(dāng)之無(wú)愧。正如《.NET大局觀》一書能夠讓讀者全攬.NET,本書講述了C++中最核心
的全部主題。書雖不厚,內(nèi)容精煉,不失為《C++ Primer》讀者茶余飯后的主題回
顧之作。
(3) 《The C++ Programming Language》
Bjarne為你帶來(lái)的C++教程,真正能夠告訴你怎么用才叫真正的C++的唯一一本
書。雖然如同“某某程序設(shè)計(jì)語(yǔ)言”這樣的書籍會(huì)給大家一個(gè)內(nèi)容全攬,入門到精
通的感覺(jué),但本書確實(shí)不太適合初學(xué)者閱讀。如果你自認(rèn)為是一名很有經(jīng)驗(yàn)的C++程
序員,那至少也要反復(fù)咀嚼Bjarne先生所強(qiáng)調(diào)的若干內(nèi)容。
(4) 《Effective C++》,《More Effective C++》
是的,正如一些C++愛(ài)好者經(jīng)常以讀過(guò)與沒(méi)有讀過(guò)上述兩本作品來(lái)區(qū)分你是否是
C++高手。我們也極力推崇這兩本著作。在各種介紹C++專家經(jīng)驗(yàn)的書籍里面,這兩
本是最貼近語(yǔ)言本質(zhì),看后最能夠有脫胎換骨感覺(jué)的書,讀此書你需每日三省汝身
。
技術(shù)書籍仁者見(jiàn)仁,過(guò)多的評(píng)論反無(wú)太多意義,由讀者喜好選擇最適合自己的
書方為上策。
------------------------------------------------------------------------
--------
7,資源網(wǎng)站
正如我們可以通過(guò)計(jì)算機(jī)歷史上的重要人物了解計(jì)算機(jī)史的發(fā)展,C++相關(guān)人物
的網(wǎng)站也可以使我們得到最有價(jià)值的參考與借鑒,下面的人物我們認(rèn)為沒(méi)有介紹的
必要,只因下面的人物在C++領(lǐng)域的地位眾所周知,我們只將相關(guān)的資源進(jìn)行羅列以
供讀者學(xué)習(xí),他們有的工作于貝爾實(shí)驗(yàn)室,有的工作于知名編譯器廠商,有的在不
斷推進(jìn)語(yǔ)言的標(biāo)準(zhǔn)化,有的為讀者撰寫了多部千古奇作……
(1) Bjarne Stroustrup
http://www.research.att.com/~bs/
(2) Stanley B. Lippman
http://blogs.msdn.com/slippman/
中文版 http://www.zengyihome.net/slippman/index.htm
(3) Scott Meyers
http://www.aristeia.com/
(4) David Musser
http://www.cs.rpi.edu/~musser/
(5) Bruce Eckel
http://www.bruceeckel.com
(6) Nicolai M. Josuttis
http://www.josuttis.com/
(7) Herb Sutter
http://www.gotw.ca/
(8) Andrei Alexandrescu
http://www.coderncppdesign.com/
(9) 侯捷先生
http://www.jjhou.com
(10) 孟巖先生
先生繁忙于工作,癡迷于技術(shù),暫無(wú)個(gè)人主頁(yè),關(guān)于先生的作品可以通過(guò)CSDN
的專欄和侯先生的主頁(yè)訪問(wèn)到。
(11) 榮耀先生
http://www.royaloo.com/
(12) 潘愛(ài)民先生
http://www.icst.pku.edu.cn/panaimin/pam_homepage.htm
除了上述大師的主頁(yè)外,以下的綜合類C++學(xué)習(xí)參考站點(diǎn)是我們非常愿意向大家
推薦的:
(1) CodeProject
http://www.codeproject.com
(2) CodeGuru
http://www.codeguru.com
(3) Dr. Dobb's Journal
http://www.ddj.com
(4) C/C++ Users Journal
http://www.cuj.com
(5) C維視點(diǎn)
http://www.c-view.org
(6) allaboutprogram
http://www.allaboutprogram.com
其他資料
(1) ISO IEC JTC1/SC22/WG21 - C++:標(biāo)準(zhǔn)C++的權(quán)威參考
http://anubis.dkuug.dk/jtc1/sc22/wg21/
(2) C++ FAQ LITE — Frequently Asked Questions: 最為全面的C++FAQ
http://www.sunistudio.com/cppfaq/index.html
C/C++ 新聞組:
你不妨嘗試從這里提問(wèn)和回答問(wèn)題,很多不錯(cuò)的Q&A資源......
(1) .alt.comp.lang.learn.c-c++
這個(gè)簡(jiǎn)單些,如果你和我一樣是個(gè)菜鳥(niǎo)
(2) .comp.lang.c++.moderated
嗯,這個(gè)顯然水平高一些
(3) .comp.std.c++
如果你需要討論標(biāo)準(zhǔn)C++相關(guān)話題的話
------------------------------------------------------------------------
--------
8,不得不寫的結(jié)束語(yǔ)
結(jié)束的時(shí)候也是總結(jié)現(xiàn)狀,展望未來(lái)的時(shí)候。雖然C++從脫胎于C開(kāi)始,一路艱
難坎坷的走過(guò)來(lái),但是無(wú)論如何C++已經(jīng)取得了工業(yè)基礎(chǔ)的地位。文章列舉的大量相關(guān)
資源就是最好的證明,而業(yè)界的大量用C++寫成的產(chǎn)品代碼以及大量的C++職業(yè)工程
師則是最直接的證明。同時(shí),我們可以看到各個(gè)高校的計(jì)算機(jī)專業(yè)都開(kāi)設(shè)有C++這門
課程,網(wǎng)絡(luò)上對(duì)于C++的學(xué)習(xí)討論也從來(lái)都沒(méi)有停過(guò)。但是,在Java和.NET兩大企業(yè)
開(kāi)發(fā)平臺(tái)的圍攻下,給人的感覺(jué)是C++越來(lái)越“不行”了。
C++在面向企業(yè)的軟件開(kāi)發(fā)中,在開(kāi)發(fā)便捷性等方面的確要比Java和C#差很多,
其中一個(gè)問(wèn)題是C++語(yǔ)言本身比較復(fù)雜,學(xué)習(xí)曲線比較陡峭,另外一個(gè)問(wèn)題是C++標(biāo)
準(zhǔn)化的時(shí)間太長(zhǎng),喪失了很多的壯大機(jī)會(huì),耗費(fèi)了很多精力在廠商的之間的斗爭(zhēng)上
,而C++的標(biāo)準(zhǔn)庫(kù)離一個(gè)完善的程序開(kāi)發(fā)框架還缺少太多太多的內(nèi)容,各個(gè)第三方的
類庫(kù)和框架又在一致性和完整性上沒(méi)法和隨平臺(tái)提供的框架相提并論。難道C++真的
要退出歷史舞臺(tái)了?
從C++目前的活躍程度,以及應(yīng)用現(xiàn)狀來(lái)說(shuō)是完全能夠肯定C++仍然是軟件工業(yè)
的基礎(chǔ),也不會(huì)退出歷史舞臺(tái)的。另外從Boost,Loki這些庫(kù)中我們也能夠看到C++
的發(fā)展非常活躍,對(duì)于新技術(shù)新思維非常激進(jìn),C++仍然廣泛受到關(guān)注。從ACE在高
性能通信領(lǐng)域的應(yīng)用,以及MTL這樣的庫(kù)在數(shù)值計(jì)算領(lǐng)域的出色表現(xiàn),我們可以看到
C++在高性能應(yīng)用場(chǎng)合下的不可替代的作用,而嵌入式系統(tǒng)這樣的內(nèi)存受限開(kāi)發(fā)平臺(tái)
,比如Symbian OS上,C++已經(jīng)發(fā)揮著并且將發(fā)揮更大的作用。可以預(yù)見(jiàn)的是以后的
軟件無(wú)論上層的應(yīng)用怎么變,它的底層核心都會(huì)是由C/C++這樣的系統(tǒng)級(jí)軟件編寫的
,比如Java虛擬機(jī),.NET Framwork。因?yàn)橹挥羞@樣的系統(tǒng)級(jí)軟件才能完全徹底的發(fā)
揮機(jī)器的功能。
需要看到的是兩個(gè)趨勢(shì),一個(gè)趨勢(shì)是C++變得更加復(fù)雜,更加學(xué)院派,通過(guò)模板
等有潛力的語(yǔ)法因素構(gòu)造越來(lái)越精巧的庫(kù)成為了現(xiàn)代C++的熱點(diǎn),雖然在利用庫(kù)實(shí)現(xiàn)
新的編程范式,乃至設(shè)計(jì)模式等方面很有開(kāi)創(chuàng)意義,也確實(shí)產(chǎn)生了一些能夠便捷開(kāi)
發(fā)的工具,但是更多的是把C++變得更加強(qiáng)大,更加復(fù)雜,也更加難懂,似乎也更加
學(xué)院派,不得不說(shuō)它正在向邊緣化道路發(fā)展。另一個(gè)趨勢(shì)是C++在主流的企業(yè)應(yīng)用開(kāi)
發(fā)中已經(jīng)逐漸退出了,ERP這樣的企業(yè)軟件開(kāi)發(fā)中基本上不會(huì)考慮C++,除非需要考
慮性能或者和遺留代碼的集成這些因素。C++退守到系統(tǒng)級(jí)別語(yǔ)言,成為軟件工業(yè)的
基礎(chǔ)是大勢(shì)所趨。然而反思一下,真的是退守么?自從STL出現(xiàn),無(wú)數(shù)的人風(fēng)起云涌
的開(kāi)始支持C++,他們狂呼“我看到深夜消失了,目標(biāo)軟件工程的出現(xiàn)。我看到了可
維護(hù)的代碼。”是的,STL在可維護(hù)性下做得如此出色。但是又怎樣呢?STL為C++鋪
平了現(xiàn)代軟件工程的道路,而在上層應(yīng)用程序軟件開(kāi)發(fā)領(lǐng)域這塊場(chǎng)地早不單獨(dú)屬于
C++,很多程序設(shè)計(jì)語(yǔ)言都做得很出色,瘋狂的支持者會(huì)毫不猶豫地說(shuō)我們應(yīng)當(dāng)支持
C++,因?yàn)樗鞘澜缟献畎舻恼Z(yǔ)言。而坦率地說(shuō),你的腰桿真的那么硬么?也許只是
在逃避一些事實(shí)。C++是優(yōu)秀的,這不可否認(rèn),STL的出現(xiàn)讓C++一度走上了最輝煌的
時(shí)刻,然而現(xiàn)在看來(lái)……我的一位恩師曾言:真正能夠?qū)TL應(yīng)用得淋漓盡致的人很
保守地說(shuō)國(guó)內(nèi)也不超過(guò)200人,或許不加入STL能夠使C++向著它應(yīng)當(dāng)發(fā)展的方向發(fā)展
的更好,而現(xiàn)在看來(lái),C++也應(yīng)當(dāng)回首到真正屬于他的那一片圣地上……
摘要: C++ / STL
[edit]
Introduction / Help
C++ slides Optimisations, Templates and good use of heritage and polymorphisms (http://www.rz.rwth-aachen.de/computing/events/2002/hpc++/HPC++1.18-1.pdf...
閱讀全文
LuaPlus上手指南(1)
版權(quán)所有,轉(zhuǎn)載請(qǐng)注明出處,勿用于商業(yè)用途,謝謝!
作者: 大寶天天見(jiàn)
Blog: http://www.shnenglu.com/singohgod
本人水平有限,有錯(cuò)請(qǐng)指出,歡迎交流,共同進(jìn)步!

國(guó)內(nèi)關(guān)于Lua的資料實(shí)在是太少,為了尋找一個(gè)合適的Lua的C++封裝,真是如同大海撈針.在看了眾多資料后鎖定以下幾種:LuaBind ToLua++ LuaPlus.在選擇上頗有諷刺的味道,LuaBind的版本號(hào)還沒(méi)到1.0,加上網(wǎng)友頗有微詞,放棄.ToLua++本來(lái)有朋友推薦,但是怎么都找不到下載,官網(wǎng)就是打不開(kāi),無(wú)賴放棄.就只有LuaPlus了,看到一些人的評(píng)價(jià)還行,于是決定就用它吧.
LuaPlus的資料就更少了,連怎么配置怎么調(diào)試等什么都沒(méi)有,只有沐楓大哥講解了語(yǔ)法方面的一篇文章.啊喲,怎么搞呢,難道又只有硬著頭皮上了?(某偉人曾說(shuō)過(guò),但凡杰出的事都是硬著頭皮干出來(lái)滴)
好了,言歸正傳,下面講講我的經(jīng)驗(yàn)吧:
如何編譯
1. 下載
首先到官方網(wǎng)站下載: http://www.luaplus.org/
下載這個(gè): All source code: http://luaplus.org/LuaPlus51_Build1100.zip (我當(dāng)前的版本,當(dāng)然越新越好)
2. 剝離
解開(kāi)下載包,打開(kāi) \LuaPlus51_Build1100\Src\LuaPlus 里面是全部源文件,src下是lua的源文件.這里有個(gè)令人疑惑的地方,源文件中帶了一些不需要的文件,要剔除去,基本上需要以下這些文件:
1) Lua庫(kù)文件:
|
lapi.c
lapi.h
lauxlib.c
lauxlib.h
lbaselib.c
lcode.c
lcode.h
ldblib.c
ldebug.c
ldebug.h
ldo.c
ldo.h
ldump.c
lfunc.c
lfunc.h
lgc.c
lgc.h
linit.c
|
liolib.c
llex.c
llex.h
llimits.h
lmathlib.c
lmem.c
lmem.h
loadlib.c
lobject.c
lobject.h
lopcodes.c
lopcodes.h
loslib.c
lparser.c
lparser.h
lstate.c
lstate.h
lstring.c
|
lstring.h
lstrlib.c
ltable.c
ltable.h
ltablib.c
ltm.c
ltm.h
lua.h
luaconf.h
lualib.h
lundump.c
lundump.h
lvm.c
lvm.h
lzio.c
lzio.h
print.c
|
2) LuaPlus頭文件:
|
auxiliar.h
LuaAutoBlock.h
LuaCall.h
LuaFunction.h
LuaHelper.h
LuaHelper_Object.h
LuaHelper_StackObject.h
LuaLink.h
LuaObject.h
LuaObject.inl
LuaPlus.h
LuaPlusCD.h
|
LuaPlusFunctions.h
LuaPlusInternal.h
LuaStackObject.h
LuaStackObject.inl
LuaStackTableIterator.h
LuaState.h
LuaState.inl
LuaStateOutFile.h
LuaTableIterator.h
luathread.h
pt.h
srm.h
|
3) LuaPlus源文件
|
LuaCall.cpp
LuaObject.cpp
LuaPlus.cpp
LuaPlusAddons.c
LuaPlusFunctions.cpp
LuaPlus_Libs.cpp
LuaStackObject.cpp
|
LuaStackTableIterator.cpp
LuaState.cpp
LuaStateOutFile.cpp
LuaState_DumpObject.cpp
LuaTableIterator.cpp
lwstrlib.c
|
3. 建立項(xiàng)目
然后你就可以在VS中建立一個(gè)新項(xiàng)目,靜態(tài)鏈接庫(kù)的:

分別把需要的文件加進(jìn)去,之后編譯,應(yīng)該能通過(guò)了.
如何使用
接著講講如何在你的其他項(xiàng)目中使用LuaPlus.
1.必要的配置
你的項(xiàng)目可能是這樣的:

設(shè)置GameClient的依賴項(xiàng)是LuaPlusLib
#include "LuaPlus.h"
using namespace LuaPlus;
記得干這事…
2.創(chuàng)建一個(gè)狀態(tài)
LuaStateOwner state;
今后的操作都圍繞這個(gè)state
3.執(zhí)行腳本
int iret = state->DoFile("test.lua");
返回值為0表示成功,否則不成功.
4.C++中獲取Lua腳本的變量
假設(shè)你的test.lua中有:
health = 200;
通過(guò)下列方法就可以在C++中得到這個(gè)數(shù)值
int mytest = state->GetGlobal("health").GetInteger();
5.C++中調(diào)用Lua腳本里的函數(shù)
假設(shè)你的test.lua中有:
function Add(x, y)
return x+y;
end
在C++中需要先聲明這個(gè)函數(shù):
LuaFunction<float> Add = state->GetGlobal("Add");
這樣你就有了Add()這個(gè)函數(shù),然后就可以像平常一樣使用它了:
float myret = Add(3.14f,5.25f);
6.Lua腳本中調(diào)用C++函數(shù)
在讀取test.lua之前要先把C++函數(shù)注冊(cè)到Lua的運(yùn)行時(shí)棧里,這樣在執(zhí)行lua腳本的時(shí)候,才知道執(zhí)行哪一個(gè)函數(shù):
首先有函數(shù):
int LS_PrintNumber(LuaState* state)
{
LuaStack args(state);
if (args[1].IsNumber()) {
printf("%f\n", args[1].GetNumber());
}
return 0;
}
然后注冊(cè)這個(gè)函數(shù)到Lua:
state->GetGlobals().Register("PrintNumber", LS_PrintNumber);
這樣就把LS_PrintNumber映射為Lua中可以使用的函數(shù)PrintNumber.
Test.lua腳本中添加調(diào)用語(yǔ)句:
PrintNumber(30);
當(dāng)state->DoFile("test.lua");執(zhí)行的時(shí)候,就執(zhí)行了C++中的這個(gè)函數(shù).
總結(jié)
本文介紹了LuaPlus的基本配置方法和使用,希望對(duì)你有幫助.下一篇將介紹一些高級(jí)特性,如怎樣在VS中調(diào)試LuaPlus的腳本,以及對(duì)類的操作等.
如果還有任何疑問(wèn)可以看看下面這個(gè)簡(jiǎn)單的例子:
/Files/singohgod/LuaPlus_Test.rar