??xml version="1.0" encoding="utf-8" standalone="yes"?> 回到主题Q记录一下镜面反矩늚推导?/p> 在用Irrlicht和RTT做镜面效果的时候,用到了反矩c?是需要把摄相机镜像,渲染一个RTQ脓到镜面模型上。这个其实还U结了许久,因ؓ之前做水面渲染的时候,水面是^的,很好计算摄相机在水面以下的位|?但是换成镜面Q就不一样了Q因为镜面可能是L面?于是需要一个通用的反矩c?/p> 反射矩阵的计是Zq面的,因ؓQQ何反,都需要一个反面?/p> 所以,我们先给出^面表C?Plane(nx,ny,nz,d); 其中(nx,ny,nz)已经单位化?/p> 然后Q我们假讄间中有Q意一点P(x,y,z,1) 设这个点P以Plane为反面的镜像点为P1(x1,y1,z1,w)?/p> Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q-Q?/p> Ҏ定理Q我们知道, 若两个点以某一点ؓ镜像Q则两个点的坐标之和除以2Q就刚好是中炏V? q个理论我们用到q里的话Q?那这个中点就刚好是^面上的一个点?q面上的q个点就?P(x,y,z,1) - (nx,ny,nz,0)*D . 其中D是点P到^面的距离 而D=Plane dot P = (x*nx+y*ny+z*nz+d); ׃面的描述Q我们马上想刎ͼ那么要求点P1的话Q就是这?nbsp; (P+P1)/2 = P(x,y,z,1) - (nx,ny,nz,0)*D => P1 = P(x,y,z,1) - 2(nx,ny,nz,0)*D =>P1 = P(x,y,z,1) - 2(nx,ny,nz,0)*(x*nx+y*ny+z*nz+d) 换成矩阵形式则ؓ ?-2*nx*nx -2*nx*ny -2*nx*nz 0 | | -2*ny*nx 1 - 2*ny*ny -2*ny*nz 0 | P1 = {x,y,z,1} x | -2*nz*nx -2*nz*ny 1-2*nz*nz 0 | | -2*d*nx -2*d*ny -2*d*nz 1 | 大功告成 btw:q是行主矩阵表示?/p> qx大家使用 epoll 旉知道其事件触发模式有默认?level-trigger 模式和通过 EPOLLET 启用?edge-trigger 模式两种。从 epoll 发展历史来看Q它刚诞生时只有 edge-trigger 模式Q后来因Ҏ产生 race-cond 且不易被开发者理解,又增加了 level-trigger 模式q作为默认处理方式?/span> 二者的差异在于 level-trigger 模式下只要某?fd 处于 readable/writable 状态,无论什么时候进?epoll_wait 都会q回?fdQ?edge-trigger 模式下只有某?fd ?unreadable 变ؓ readable 或从 unwritable 变ؓ writable Ӟepoll_wait 才会q回?fd?/span> 通常的误区是Qlevel-trigger 模式?epoll 池中存在大量 fd 时效率要显著低于 edge-trigger 模式?/strong> 但从 kernel 代码来看Qedge-trigger/level-trigger 模式的处理逻辑几乎完全相同Q差别仅在于 level-trigger 模式?event 发生时不会将其从 ready list 中移除,略ؓ增大?event 处理q程?kernel space 中记录数据的大小?/span> 然而,edge-trigger 模式一定要配合 user app 中的 ready list l构Q以便收集已出现 event ?fdQ再通过 round-robin 方式挨个处理Q以此避免通信数据量很大时出现忙于处理热点 fd 而导致非热点 fd 饿死的现象。统?kernel ?user spaceQ由?user app ?ready list 的实现千奇百怪,不一定都l过仔细的推敲优化,因此 edge-trigger 的d存开销往往q大?level-trigger 的开销?/span> 一般号U?edge-trigger 模式的优势在于能够减?epoll 相关pȝ调用Q这话不假,?user app 里可不是只有 epoll 相关pȝ调用吧?Zl过饿死问题Qedge-trigger 模式?user app 要自行进?read/write 循环处理Q这其中增加的系l调用和减少?epoll pȝ调用加v来,有谁能说一定就能明昑֜快v来呢Q?/span> 实际上,epoll_wait 的效率是 O(ready fd num) U别的,因此 edge-trigger 模式的真正优势在于减了每次 epoll_wait 可能需要返回的 fd 数量Q在q发 event 数量极多的情况下能加?epoll_wait 的处理速度Q但别忘了这只是针对 epoll 体系自己而言的提升,与此同时 user app 需要增加复杂的逻辑、花Ҏ多的 cpu/mem 与其配合工作QM性能收益I竟如何Q只有实际测量才知道Q无法一概而论。不q,Z降低处理逻辑复杂度,常用的事件处理库大部分都选择?level-trigger 模式Q如 libevent、boost::asio{) l论Q?br style="margin: 0px; padding: 0px; " />• epoll ?edge-trigger ?level-trigger 模式处理逻辑差异极小Q性能试l果表明常规应用场景 中二者性能差异可以忽略?br style="margin: 0px; padding: 0px; " />• 使用 edge-trigger ?user app 比?level-trigger 的逻辑复杂Q出错概率更高?br style="margin: 0px; padding: 0px; " />• edge-trigger ?level-trigger 的性能差异主要在于 epoll_wait pȝ调用的处理速度Q是否是 user app 的性能瓉需要视应用场景而定Q不可一概而论?/strong> Ƣ迎此话题q行深入调研、讨论! 参考资料: By QingWu q里不是主要说内存池Q只是觉得这个内存池中的指针用得很飘逸! 单提CZ下: unsigned char** next = (unsigned char**)mStartPotinter; mStartPotinter作ؓ二维指针的时候,相当于是一pd的unsigned char* []. 对于W一?*next 相当?unsigned char*)mStartPointer[0]. W二个相当于(unsigned char*)mStartPointer[sizeof(T)*1]; W三个相当于(unsigned char*)mStartPointer[sizeof(T)*2]; 所以,构造BLOCK之间关系的时候,也可以写?/p>
不想多解释了Q篏。估计多看几分种啥都明白了! 剖析 epoll ET/LT 触发方式的性能差异误解Q定性分析)
• linux kernel sourceQfs/eventpoll.c
• “Comparing and Evaluating epoll, select, and poll Event
Mechanisms”Qhttp://bcr2.uwaterloo.ca/~brecht/papers/getpaper.php?file=ols-2004.pdf
• “Edge-triggered interfaces are too difficult?”Qhttp://lwn.net/Articles/25137/
/*
0 黑色 1 p Q绿 Q浅?br> Q暗U Q暗紫 Q嫩黄 Q浅?br> Q浅灰 Q亮蓝 Q0亮绿 Q1非常?br> Q2大红 Q3亮 Q4黄 Q5白
*/
q是那段代码。我已做成了ANSI和UNICODE都支持的版本Q具体ؓ什么要q样Q可以看前一关于字W编码与IO的问题?br>
void __Printfc(U16 color, const TCHAR* format,
)
{
va_list argList;
U16 oldcolor;
HANDLE hCon=GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO bInfo;
GetConsoleScreenBufferInfo(hCon, &bInfo );
oldcolor = bInfo.wAttributes;
if(oldcolor!=color)
SetConsoleTextAttribute(hCon,color);
#ifdef _UNICODE
_tsetlocale(LC_CTYPE,TEXT(""));
#endif
va_start( argList, format );
_tprintf( format,argList);
va_end( argList );
#ifdef _UNICODE
_tsetlocale(LC_CTYPE,TEXT("C"));
#endif
if(oldcolor!=color)
SetConsoleTextAttribute(hCon,color);
}
用百度搜了一下这个输出问题,H然发现了其中奥妙,原来Unicode需要本地化信息?br> l测试发C如下规律
/*
C?nbsp; CU 非C? 非CU
stdio 1 0 1 1
iostream 1 1 0 0
可以得出
Q、在多字节时Q默?CQ风gQ二者都能输Z文?br>Q、在多字节时Q非C风格下,cout不能输出中文
Q、在UӞ默认C风格下,print不能输出中文
Q、在UӞ非C风格下,cout不能输出中文
由此可知Q要在C风格下,iostream才能输出中文?br>而printf只有在C风格的Unicode下才不能输出中文Q其它均可?/font>
*/
试代码如下
#include <iostream>
#include <tchar.h>
#include <locale>
int _tmain(int argc, _TCHAR* argv[])
{
#ifdef _UNICODE
_tsetlocale(LC_CTYPE,TEXT(""));
#endif
_tprintf(TEXT("a在哪里啊\n"));
#ifdef _UNICODE
_tsetlocale(LC_CTYPE,TEXT("C"));
#endif
#ifdef _UNICODE
std::wcout<<"d在哪里啊"<<std::endl;
#else
std::cout<<"d在哪里啊"<<std::endl;
#endif
getchar();
return 0;
}
其中三维模型导入是用OPENGL+GLUT+VS 2005
墙中公主?D贪食蛇是用的D3DAPI+VC6.0 阅读全文
q里我简要的Ҏ自己的经验列试中比较常用的技巧,希望对大家有用?nbsp; 阅读全文
阅读全文
阅读全文
不知道各位有何高见!
我心中也有一个答案。但先不_大家一h讨论。。?共同完成q篇贴子?随后Q大家的高端回复会以如下方式出现
如果不希望最后出现在q里Q请大家注明?默认情况下,表示同意Q?
IDQXXXX
解释Q?****************
=======================
IDQXXXXX
解释Q?******************* 阅读全文
我们需要弄清两点:1、main函数中的p与MyNew函数中的p是不是一P2、如果不一P是怎么D了不一L?
阅读全文
阅读全文template <class T,int AllocSize = 50>
2class MemPool
3{
4public:
5 static void* operator new(size_t allocLength)
6
{
7 if(!mStartPotinter)
8
{
9 MyAlloc();
10 }
11 //当前指向空闲内存v始地址作ؓ反回地址
12 unsigned char* p = mStartPotinter;
13 //取出I闲区域?字节的|赋值给I闲地址
14 //因ؓ前四字节中存放了下一个BLOCK的地址
15 mStartPotinter = *(unsigned char**)mStartPotinter;
16 return p;
17 }
18
19 static void operator delete(void* deleteP)
20
{
21// assert(deletePointer);
22 *(unsigned char**)deleteP = mStartPotinter;
23 mStartPotinter = (unsigned char*)deleteP;
24 }
25
26 static void MyAlloc()
27
{
28 //预分配内?nbsp;
29 mStartPotinter = new unsigned char[sizeof(T)*AllocSize];
30 //构造BLOCK之间的关p?nbsp;
31 //每个BLOCK的前4BYTE存放了下一个BLOCK的地址
32 unsigned char** next = (unsigned char**)mStartPotinter;
33 unsigned char* p = mStartPotinter;
34
35 for(int i = 0; i< AllocSize;++i)
36
{
37 p +=sizeof(T);//步进
38 *next = p;//赋?nbsp;
39 next = (unsigned char**)p;//步进
40 }
41 *next = NULL;
42 }
43
44 static unsigned char* mStartPotinter;
45};
46
47template <class T,int AllocSize>
48unsigned char* MemPool<T,AllocSize>::mStartPotinter = NULL;
49
50
51本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/wqjqepr/archive/2010/05/03/5552322.aspx
for(int i = 0; i< AllocSize;++i)
2{
3 p +=sizeof(T);//步进
4 unsigned char* pp = (unsigned char*)(p[sizeof(T)*i]);
5 pp = p;//赋?nbsp;
6}
1Q有成员变量的情c?
2Q有重复l承的情c?
3Q有虚拟l承的情c?
4Q有ȝ型虚拟承的情况?
q有Q对于前几天的脓子表C报歉,今天是直接脓到这里的?没ؕ码,q好Q!Q?nbsp; 阅读全文
关于虚函数的使用ҎQ我在这里不做过多的阐述。大家可以看看相关的C++的书c。在q篇文章中,我只想从虚函数的实现机制上面为大?一个清晰的剖析?
当然Q相同的文章在网上也出现q一些了Q但我L觉这些文章不是很Ҏ阅读Q大D大D늚代码Q没有图片,没有详细的说明,没有比较Q没有D一反三。不利于学习和阅读,所以这是我惛_下这文章的原因。也希望大家多给我提意见?
a归正传,让我们一赯入虚函数的世界?
虚函数表
对C++ 了解的h都应该知道虚函数QVirtual FunctionQ是通过一张虚函数表(Virtual TableQ来实现的。简UCؓV-Table?在这个表中,L要一个类的虚函数的地址表,q张表解决了l承、覆盖的问题Q保证其容真实反应实际的函数。这P在有虚函数的cȝ实例中这个表被分配在?q个实例的内存中Q所以,当我们用父类的指针来操作一个子cȝ时候,q张虚函数表显得由为重要了Q它像一个地图一P指明了实际所应该调用的函数?
q里我们着重看一下这张虚函数表。在C++的标准规D明书中说刎ͼ~译器必需要保证虚函数表的指针存在于对象实例中最前面的位|(q是Z保证正确取到虚函数的偏移量)?q意味着我们通过对象实例的地址得到q张虚函数表Q然后就可以遍历其中函数指针Qƈ调用相应的函数?
听我扯了那么多,我可以感觉出来你现在可能比以前更加晕头{向了?没关p,下面是实际的例子,怿聪明的你一看就明白了?
假设我们有这L一个类Q?
class Base {
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};
按照上面的说法,我们可以通过Base的实例来得到虚函数表?下面是实际例E:
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout << "虚函数表地址Q? << (int*)(&b) << endl;
cout << "虚函数表 ?W一个函数地址Q? << (int*)*(int*)(&b) << endl;
// Invoke the first virtual function
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
实际q行l果如下Q?Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3)
虚函数表地址Q?012FED4
虚函数表 ?W一个函数地址Q?044F148
Base::f
通过q个CZQ我们可以看刎ͼ我们可以通过?amp;b转成int *Q取得虚函数表的地址Q然后,再次取址可以得到第一个虚函数的地址了,也就是Base::f()Q这在上面的E序中得C验证Q把int* 强制转成了函数指针)。通过q个CZQ我们就可以知道如果要调用Base::g()和Base::h()Q其代码如下Q?
(Fun)*((int*)*(int*)(&b)+0); // Base::f()
(Fun)*((int*)*(int*)(&b)+1); // Base::g()
(Fun)*((int*)*(int*)(&b)+2); // Base::h()
q个时候你应该懂了吧。什么?q是有点晕。也是,q样的代码看着太ؕ了。没问题Q让我画个图解释一下。如下所C:
注意Q在上面q个图中Q我在虚函数表的最后多加了一个结点,q是虚函数表的结束结点,像字符串的l束W?#8220;\0”一P其标志了虚函数表的结束。这个结束标志的值在不同的编译器下是不同的。在WinXP+VS2003下,q个值是NULL。而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下,q个值是如果1Q表C有下一个虚函数表,如果值是0Q表C是最后一个虚函数表?
下面Q我分别说?#8220;无覆?#8221;?#8220;有覆?#8221;时的虚函数表的样子。没有覆盖父cȝ虚函数是毫无意义的。我之所以要讲述没有覆盖的情况,主要目的是ؓ了给一个对比。在比较之下Q我们可以更加清楚地知道其内部的具体实现?
一般承(无虚函数覆盖Q?br>下面Q再让我们来看看l承时的虚函数表是什么样的。假设有如下所C的一个承关p:
h意,在这个承关pMQ子cL有重载Q何父cȝ函数。那么,在派生类的实例中Q其虚函数表如下所C:
对于实例QDerive d; 的虚函数表如下:
我们可以看到下面几点Q?
1Q虚函数按照其声明顺序放于表中?
2Q父cȝ虚函数在子类的虚函数前面?
我相信聪明的你一定可以参考前面的那个E序Q来~写一D늨序来验证?
一般承(有虚函数覆盖Q?br>覆盖父类的虚函数是很昄的事情,不然Q虚函数变得毫无意义。下面,我们来看一下,如果子类中有虚函数重载了父类的虚函数Q会是一个什么样子?假设Q我们有下面q样的一个承关pR?
Z让大家看到被l承q后的效果,在这个类的设计中Q我只覆盖了父类的一个函敎ͼf()。那么,对于zcȝ实例Q其虚函数表会是下面的一个样子:
我们从表中可以看C面几点,
1Q覆盖的f()函数被放C虚表中原来父c虚函数的位|?
2Q没有被覆盖的函C旧?
q样Q我们就可以看到对于下面q样的程序,
Base *b = new Derive();
b->f();
由b所指的内存中的虚函数表的f()的位|已l被Derive::f()函数地址所取代Q于是在实际调用发生Ӟ是Derive::f()被调用了。这实C多态?
多重l承Q无虚函数覆盖)
下面Q再让我们来看看多重l承中的情况Q假设有下面q样一个类的承关pR注意:子类q没有覆盖父cȝ函数?
对于子类实例中的虚函数表Q是下面q个样子Q?
我们可以看到Q?
1Q?每个父类都有自己的虚表?
2Q?子类的成员函数被攑ֈ了第一个父cȝ表中。(所谓的W一个父cL按照声明序来判断的Q?
q样做就是ؓ了解决不同的父类cd的指针指向同一个子cd例,而能够调用到实际的函数?
多重l承Q有虚函数覆盖)
下面我们再来看看Q如果发生虚函数覆盖的情c?
下图中,我们在子cM覆盖了父cȝf()函数?
下面是对于子cd例中的虚函数表的图:
我们可以看见Q三个父c虚函数表中的f()的位|被替换成了子类的函数指针。这P我们可以Q一静态类型的父类来指向子c,q调用子cȝf()了。如Q?
Derive d;
Base1 *b1 = &d;
Base2 *b2 = &d;
Base3 *b3 = &d;
b1->f(); //Derive::f()
b2->f(); //Derive::f()
b3->f(); //Derive::f()
b1->g(); //Base1::g()
b2->g(); //Base2::g()
b3->g(); //Base3::g()
安全?br>每次写C++的文章,d不了要批判一下C++。这文章也不例外。通过上面的讲qͼ怿我们对虚函数表有一个比较细致的了解了。水可蝲舟,亦可覆舟。下面,让我们来看看我们可以用虚函数表来q点什么坏事吧?
一、通过父类型的指针讉K子类自己的虚函数
我们知道Q子cL有重载父cȝ虚函数是一件毫无意义的事情。因为多态也是要Z函数重蝲的。虽然在上面的图中我们可以看到Base1的虚表中有Derive的虚函数Q但我们Ҏ不可能用下面的语句来调用子cȝ自有虚函敎ͼ
Base1 *b1 = new Derive();
b1->f1(); //~译出错
M妄图使用父类指针惌用子cM的未覆盖父类的成员函数的行ؓ都会被编译器视ؓ非法Q所以,q样的程序根本无法编译通过。但在运行时Q我们可以通过指针的方式访问虚函数表来辑ֈq反C++语义的行为。(关于q方面的试Q通过阅读后面附录的代码,怿你可以做到这一点)
二、访问non-public的虚函数
另外Q如果父cȝ虚函数是private或是protected的,但这些非public的虚函数同样会存在于虚函数表中,所以,我们同样可以使用讉K虚函数表的方式来讉Kq些non-public的虚函数Q这是很Ҏ做到的?
如:
class Base {
private:
virtual void f() { cout << "Base::f" << endl; }
};
class Derive : public Base{
};
typedef void(*Fun)(void);
void main() {
Derive d;
Fun pFun = (Fun)*((int*)*(int*)(&d)+0);
pFun();
}
前些天,~程序是用到了很久以前写的CE序Q想把里面的函数利用hQ连接发现出C找不到具体函数的错误Q?/p>
以下是假设旧的CE序?/p>
C的头文g
/*-----------c.h--------------*/
#ifndef _C_H_
#define _C_H_
extern int add(int x, int y);
#endif
C的源文g
/*-----------c.c--------------*/
int add(int x, int y){
return x+y;
}
C++的调?/p>
/*-----------cpp.cpp--------------*/
#include "c.h"
void main()
{
add(1, 0);
}
q样~译会生错误cpp.obj : error LNK2001: unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z)Q原因是找不到add的目标模?/p>
q才令我惌vC++重蝲的函数命名方式和C函数的命名方式,让我们回一下:C中函数编译后命名会在函数名前加以"_",比如add函数~译成obj文g时的实际命名为_addQ而c++命名则不同,Z实现函数重蝲同样的函数名add因参数的不同会被~译成不同的名字
例如
int add(int , int)==>add@@YAHHH@Z,
float add(float , float )==>add@@YAMMM@Z,
以上是VC6的命名方式,不同的编译器会不同,M不同的参数同L函数名将~译成不同目标名Q以便于函数重蝲是调用具体的函数?/p>
~译cpp.cpp中编译器在cpp文g中发现add(1, 0);的调用而函数声明ؓextern int add(int x, int y);~译器就军_Ladd@@YAHHH@ZQ可惜他找不刎ͼ因ؓC的源文g?font color=#990000>extern int add(int x, int y);~译成_add了;
Z解决q个问题C++采用了extern "C",q就是我们的主题Q想要利用以前的CE序库,那么你就要学会它Q我们可以看以下标准头文件你会发玎ͼ很多头文仉有以下的l构
#ifndef __H
#define __H
#ifdef __cplusplus
extern "C" {
#endif
extern int f1(int, int);
extern int f2(int, int);
extern int f3(int, int);
#ifdef __cplusplus
}
#endif
#endif /*__H*/
如果我们仿制该头文g可以得到
#ifndef _C_H_
#define _C_H_
#ifdef __cplusplus
extern "C" {
#endif
extern int add(int, int);
#ifdef __cplusplus
}
#endif
#endif /* _C_H_ */
q样~译
/*-----------c.c--------------*/
int add(int x, int y){
return x+y;
}
q时源文件ؓ*.cQ?/font>__cplusplus没有被定义,extern "C" {}q时没有生效对于C他看到只?font color=#990000>extern int add(int, int);
add函数~译成_add(int, int);
而编译c++源文?/font>
/*-----------cpp.cpp--------------*/
#include "c.h"
void main()
{
add(1, 0);
}
q时源文件ؓ*.cpp,__cplusplus被定?对于C++他看到的?font color=#990000>extern "C" {extern int add(int, int);}~译器就会知?add(1, 0);调用的C风格的函敎ͼ׃知道去c.obj中找_add(int, int)而不?/strong>add@@YAHHH@ZQ?/font>
如果 constantexpression 计算l果为非零|则处?!IF 和下一?!ELSE ?!ENDIF 之间的语句?br>!ENDIF
标记 !IF?strong>!IFDEF ?!IFNDEF 块的l尾。同一行上 !ENDIF 后面的所有文本被忽略?/p>
通过例子学习Lua(1) ---- Hello World
1.前言
游戏中少不了用到脚本语言. Lua是一U和C/C++l合非常紧密的脚本语aQ效率极高?br>一般是Ҏ间要求比较高的地方用C++写,而经帔R要改动的地方用Lua写?/p>
偶最q在学习Lua, 所以写出心得和大家׃n. Lua是一U完全免费的脚本语言,
它的官方|站?a >http://www.lua.org.在网站上可以下蝲到lua的源? 没有?br>执行版本, 不过不用担心, 因ؓlua源码可以在Q何一UC/C++的编译器上编?
如果要学习Lua, 官方|站上的Reference是必备的Q上面有每个命o的用法,非常?br>l?br>参考手?http://www.lua.org/manual/5.0/
作者写的Programming in Lua http://www.lua.org/pil/
2.~译
如果用的VC, 可以下蝲所需的project文g,地址?br>http://sourceforge.net/project/showfiles.php?group_id=32250&package_id=115604
偶用的是cygwin和linux, 打入以下命o卛_,
tar -zxvf lua-5.0.2.tar.gz
cd lua-5.0.2
sh ./configure
make
q样OK了?br>Z以后使用方便Q最好把bin目录加入到path里面?/p>
3."Hello, world!"
现在开始偶们的W一个小E序"Hello, world!"
把以下程序打入文件e01.lua
?:e01.lua
-- Hello World in Lua
print("Hello World.")
Lua有两U执行方式,一U是嵌入到CE序中执行,q有一U是直接从命令行方式下执
行?br>q里Z调试方便Q采用第二种方式Q执行命?lua e01.lua
输出l果应该是:
Hello World.
4.E序说明
W一?-- Hello World in Lua
q句是注释,其中--和C++中的//意思是一L
W二?print("Hello World.")
调用lua内部命oprintQ输?Hello World."字符串到屏幕QLua中的字符串全部是
?括v来的?br>q个命o是一个函数的调用Qprint是lua的一个函敎ͼ?Hello World."是print的参
数?/p>
5.试试?br>在Lua中有不少字符串的处理操作Q本ơ的译试试看的内容是Q找接两个字W串
的操作,
q且print出来?br>--
通过例子学习Lua(2) --- Lua基础
1. 函数的?br>以下E序演示了如何在Lua中用函? 及局部变?br>例e02.lua
-- functions
function pythagorean(a, b)
local c2 = a^2 + b^2
return sqrt(c2)
end
print(pythagorean(3,4))
q行l果
5
E序说明
在Lua中函数的定义格式?
function 函数?参数)
...
end
与Pascal语言不同, end不需要与begin配对, 只需要在函数l束后打个end可以了.
本例函数的作用是已知直角三角形直角边, 求斜辚w? 参数a,b分别表示直角辚w,
在函数内定义了local形变量用于存储斜边的qx. 与C语言相同, 定义在函数内的代
码不会被直接执行, 只有ȝ序调用时才会被执?
local表示定义一个局部变? 如果不加local刚表Cc2Z个全局变量, local的作用域
是在最里层的end和其配对的关键字之间, 如if ... end, while ... end{。全局变量
?br>作用域是整个E序?/p>
2. 循环语句
例e03.lua
-- Loops
for i=1,5 do
print("i is now " .. i)
end
q行l果
i is now 1
i is now 2
i is now 3
i is now 4
i is now 5
E序说明
q里偶们用到了for语句
for 变量 = 参数1, 参数2, 参数3 do
循环?br>end
变量以参数3为步? 由参?变化到参?
例如:
for i=1,f(x) do print(i) end
for i=10,1,-1 do print(i) end
q里print("i is now " .. i)中,偶们用到?.Q这是用来连接两个字W串的,
偶在(1)的试试看中提到的Q不知道你们{对了没有?br>虽然q里i是一个整型量QLua在处理的时候会自动转成字符串型Q不需偶们费心?/p>
3. 条g分支语句
例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
q行l果
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
E序说明
if else用法比较? cM于C语言, 不过此处需要注意的是整个if只需要一个end,
哪怕用了多个elseif, 也是一个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.试试?br>Lua中除了for循环以外, q支持多U@? Lwhile...do和repeat...until改写本文
中的forE序
--
通过例子学习Lua(3) ---- 数据l构
1.?
Lua语言只有一U基本数据结? 那就是table, 所有其他数据结构如数组?
cd, 都可以由table实现.
2.table的下?
例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
输出l果
0=foo
1=42
bar=baz
E序说明
首先定义了一个table myData={}, 然后用数字作Z标赋了两个值给? q种
定义ҎcM于C中的数组, 但与数组不同的是, 每个数组元素不需要ؓ相同cd,
像本例中一个ؓ整型, 一个ؓ字符?
E序W二部分, 以字W串做ؓ下标, 又向table内增加了一个元? q种table非常
像STL里面的map. table下标可以为Lua所支持的Q意基本类? 除了nilg?
Lua对Table占用内存的处理是自动? 如下面这D代?
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, 只占用一块内? 当执行到a = nil? b仍然指向table,
而当执行到b=nil? 因ؓ没有指向table的变量了, 所以Lua会自动释放table所占内?
3.Table的嵌?
Table的用还可以嵌套Q如下例
例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)
E序说明
首先建立一个table, 与上一例不同的是,在table的constructor里面有{x=0,y=0},
q是什么意思呢Q?q其实就是一个小table, 定义在了大table之内, table?
table名省略了.
最后一行myPolygon[2].xQ就是大table里面table的访问方?
--
通过例子学习Lua(4) -- 函数的调?
1.不定参数
例e07.lua
-- Functions can take a
-- variable number of
-- arguments.
function funky_print (...)
for i=1, arg.n do
print("FuNkY: " .. arg)
end
end
funky_print("one", "two")
q行l果
FuNkY: one
FuNkY: two
E序说明
* 如果?..为参? 则表C参数的数量不定.
* 参数会自动存储C个叫arg的table?
* arg.n中存攑֏数的个数. arg[]加下标就可以遍历所有的参数.
2.以table做ؓ参数
例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}
q行l果
x=10
y=20
E序说明
* print_contents{x=10, y=20}q句参数没加圆括? 因ؓ以单个table为参数的时?
不需要加圆括?
* for k,v in t do q个语句是对table中的所有值遍? k中存攑U? v中存攑ր?
3.把Lua变成cMXML的数据描q语a
例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
}
E序说明
* 把function和tablel合, 可以使Lua成ؓ一U类似XML的数据描q语a
* e09中contact{...}, 是一U函数的调用Ҏ, 不要弄?
* [[...]]是表C多行字W串的方?
* 当用C API时此U方式的优势更明? 其中contact{..}部分可以另外存成一配置?
?
4.试试?
x看哪些地方可以用Ce09中提到的配置Ҏ呢?
--
通过例子学习Lua(5) ---- Lua与C交互入门
1.?
Lua与C/C++l合是很紧密? Lua与C++交互是徏立在Lua与C的基上的, 所
以偶先从Lua与C讲v.
正如W一讲所? q行LuaE序或者说调用Lua主要有两U方?
* 通过命o行执?Lua"命o
* 通过Lua的C?
虽然此前偶们一直用W一U方? 但偶要告诉你, 通过Lua的C库执行才是游戏中
常用的方?
2.Lua的C?
Lua的C库可以做为Shared Library调用, 但一般开发游戏时会把Lua的所有源E序
都包含在? q不把Lua~译成共享库的Ş? 因ؓLuaE序只有100多K, 而且几乎
可以在Q何编译器下Clean Compile. 带Lua源程序的另一个好处时, 可以随时对Lua
本nq行扩充, 增加偶们所需的功?
Lua的C库提供一pdAPI:
* 理全局变量
* 理tables
* 调用函数
* 定义新函? q也可以完全由C实现
* 垃圾攉器Garbage collector, 虽然Lua可以自动q行, 但往往不是立即执行?
所以对实时性要求比较高的程? 会自p用垃圾收集器
* 载入q执行LuaE序, q也可以由Lua自n实现
* MLua可以实现的功? 都可以通过Lua的C API实现, q对于优化程序的q行速度
有帮? l常调用的共用的LuaE序片断可以转成CE序, 以提高效? qLua都是C写的
q有什么C不能实现?
3.Lua与C集成的例?
例e10.c
/* A simple Lua interpreter. */
#include <stdio.h>
#include <lua.h>
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, q把头文件放入include路径
* gcc e10.c -llua -llualib -o e10
VC6/VC2003
* 先编译Lua, 在Option中设|头文g和库文g路径
* 新徏工程,在工E配|中加入附加库lua.lib和lualib.lib
* ~译成exe
q行l果
本程序的功能是实C个Lua解释? 输入的每行字W都会被解释成Luaq执?
E序说明
* #include <lua.h> 包含lua头文? 然后才可以用API
* lua_State *L = lua_open(0) 打开一个Lua执行?
* fgets(line, sizeof(line), stdin) 从标准输入里d一?
* lua_dostring(L, line) 执行此行
* lua_close(L) 关闭Lua执行?
例e11.c
/* Another simple Lua interpreter. */
#include <stdio.h>
#include <lua.h>
#include <lualib.h>
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;
}
q行l果
本程序的功能是实C个Lua解释? 输入的每行字W都会被解释成Luaq执?
与上例不同的? 本例调用了Lua的一些标准库.
E序说明
* #include <lualib.h> 包含Lua的标准库
* 以下q几行是用来dLua的一些库, q样偶们的LuaE序可以有更多的功?
lua_baselibopen(L);
lua_iolibopen(L);
lua_strlibopen(L);
lua_mathlibopen(L);
4.试试?
把上面两个小例子在你熟悉的编译器中编译执? q试试能否与Lua源码树一L?
--
通过例子学习Lua(6) ---- C/C++中用Lua函数
参考英文文档http://tonyandpaige.com/tutorials/lua2.html
1.?
偶们q次主要说说怎么由Lua定义函数, 然后在C或者C++中调? q里偶们
暂不涉及C++的对象问? 只讨用函数的参数, q回值和全局变量的?
2.
q里偶们在e12.lua里先定义一个简单的add(), x,y为加法的两个参数,
return 直接q回相加后的l果.
例e12.lua
-- add two numbers
function add ( x, y )
return x + y
end
在前一ơ里, 偶们说到 lua_dofile() 可以直接在C中执行lua文g. 因ؓ偶们
q个E序里只定义了一个add()函数, 所以程序执行后q不直接l果, 效果相当
于在C中定义了一个函C?
Lua的函数可以有多个参数, 也可以有多个q回? q都是由?stack)实现?
需要调用一个函数时, 把q个函数压入? 然后序压入所有参? 然后?
lua_call()调用q个函数. 函数q回? q回g是存攑֜栈中. q个q程?
汇编执行函数调用的过E是一L.
例e13.cpp 是一个调用上面的Lua函数的例?
#include <stdio.h>
extern "C" { // q是个C++E序, 所以要extern "C",
// 因ؓlua的头文g都是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;
}
E序说明:
main中过E偶们上ơ已l说q了, 所以这ơ只说说luaadd的过E?
* 首先用lua_getglobal()把add函数压栈
* 然后用lua_pushnumber()依次把x,y压栈
* 然后调用lua_call(), q且告诉E序偶们有两个参C个返回?
* 接着偶们从栈取回返回? 用lua_tonumber()
* 最后偶们用lua_pop()把返回值清?
q行l果:
The sum is 25
~译Ҏ
Linux下把E序存成e13.cpp
g++ e13.cpp -llua -llualib -o e13
./e13
VC下编译方?
* 首先建立一个空的Win32 Console Application Project
* 把e13.cpp加入工程?
* 点project setting,然后讄link选项, 再加上lua.lib lualib.lib两个额外的库
* 最后编?
建立好的project可以在这里下?
VC http://tonyandpaige.com/tutorials/luaadd.zip
Linux http://tonyandpaige.com/tutorials/luaadd.tar.gz
3.全局变量
上面偶们用到了lua_getglobal()但ƈ没有详细? q里偶们再D两个例子来说下全局
变量
lua_getglobal()的作用就是把lua中全局变量的值压入栈
lua_getglobal(L, "z");
z = (int)lua_tonumber(L, 1);
lua_pop(L, 1);
假设LuaE序中定义了一个全局变量z, q段程序就是把z的值取出放入C的变量z?
另外Lua中还有一个对应的函数lua_setglobal(), 作用是用栈顶的值填充指定的全局?
?
lua_pushnumber(L, 10);
lua_setglobal(L, "z");
例如q段程序就是把lua中的全局变量z设ؓ10, 如果lua中未定义z的话, ׃自动?
Z?
全局变量zq设?0.
4.试试?
自己写个函数用C/C++来调用下试试
--
通过例子学习Lua(7) ---- Lua中调用C/C++函数
1.前言
上次偶说CC/C++中调用Lua的函? 然后有朋友问从Lua中如何调用C/C++?
函数, 所以偶们这ơ就来说说这个问? 首先偶们会在C++中徏立一个函? 然后
告知Lua有这个函? 最后再执行? 另外, ׃函数不是在Lua中定义的, 所?
无法定函数的正? 可能在调用过E中会出? 因此偶们q会说说Lua出错?
理的问题.
2.Lua中调用C函数
在lua中是以函数指针的形式调用函数, q且所有的函数指针都必L_下此U?
cd:
typedef int (*lua_CFunction) (lua_State *L);
也就是说, 偶们在C++中定义函数时必须以lua_State为参? 以int回值才?
被Lua所调用. 但是不要忘记? 偶们的lua_State是支持栈? 所以通过栈可?
传递无I个参数, 大小只受内存大小限制. 而返回的intg只是指返回值的个数
真正的返回值都存储在lua_State的栈? 偶们通常的做法是做一个wrapper, ?
所有需要调用的函数都wrap一? q样可以调用Q意的函数?
下面q个例子是一个C++的average()函数, 它将展示如何用多个参数ƈq回多个?
例e14.cpp
#include <stdio.h>
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)
E序说明:
* lua_gettop()的作用是q回栈顶元素的序? ׃Lua的栈是从1开始编L,
所以栈元素的序号也相当于栈中的元素个? 在这? 栈中元素的个数就
是传入的参数个数.
* for循环计算所有传入参数的d. q里用到了数D{换lua_tonumber().
* 然后偶们用lua_pushnumber()把^均值和dpush到栈?
* 最? 偶们q回2, 表示有两个返回?
* 偶们虽然在C++中定义了average()函数, 但偶们的LuaE序q不知道, 所以需
要在main函数中加?
/* register our function */
lua_register(L, "average", average);
q两行的作用是告诉e15.lua有average()q样一个函?
* q个E序可以存成cpp也可以存成c, 如果?c为扩展名׃需要加extern "C"
~译的方法偶们上ơ说q了, Ҏ相同.
e15.lua执行的方法只能用上例中的C++中执? 而不能用命o行方式执?
3.错误处理
在上例中, 偶们没有对传入的参数是否为数字进行检? q样做不? 所以这里偶
们再加上错误处理的片?
把这D加在for循环之内:
if (!lua_isnumber(L, i)) {
lua_pushstring(L, "Incorrect argument to 'average'");
lua_error(L);
}
q段的作用就是检传入的是否为数?
加上q段之后, 偶们debug的时候就会简单许? 对于l合两种语言的编E? 它们?
间传递数据的正确性检是非常重要?
q里有别人写好的例子:
VC?http://tonyandpaige.com/tutorials/luaavg.zip
Linux?http://tonyandpaige.com/tutorials/luaavg.tar.gz
x, Lua与C的结合就基本讲完? 下次偶要开始说说Lua与面向对?
但是偶自p没有学完, 所以大家可能要多等两天? Sorry!
--
//用于2字节QDWORD)数据填充的函?br>inline void Mem_Set_WORD(VOID *dest, USHORT data, int count )
{
_asm
{
mov edi, dest ; edi指向目标内存
mov ecx, count ;要移动的16位字?br> mov ax, data ;16位数?br> rep stosw ;Ud数据
?/end asm
}//end Mem_Set_WORD
int Partition(int a[],int l,int r)
{
int p = a[l];//取首元素作ؓ划分?/p>
while(l<r)
{
while(l<r&& a[r]>=p)
--r;
a[l] = a[r];
while(l<r&& a[l]<=p)
++l;
a[r] = a[l];
}
a[l] = p;
return l;
}
void QSort(int a[],int l,int r)
{
int p;
if(l<r)
{
p = Partition(a,l,r);
for(int i = l; i< r;++i)
{
cout<<a[i]<<" ";
}
cout<<endl;
QSort(a,l,p-1);
QSort(a,p+1,r);
}
}