??xml version="1.0" encoding="utf-8" standalone="yes"?>
(setq auto-mode-alist (cons '(".proto$" . protobuf-mode) auto-mode-alist))
工具栏上多了个ProtocolBuffers菜单Q有一些简单功能,如注释某D代码,代码跌{{等?br />
]]>
因此如a[i]q样的访问都被编译器改写或解释ؓ(f)*(a+i)的Ş式,同样取下标操作符的操作数是可交换的,所以a[3]可以写成3[a]Q不q通常你不?x)这样做?br />
2、下标L与指针的偏移量相同,下标*sizeof(元素cd)是偏移数组起始地址的实际字节数?br />
3?#8220;作ؓ(f)函数参数的数l名”{同于指针,M传递给函数的数l参数都?x)被转换成指针,q是Z效率考虑Q避免了数组的拷贝。在函数内部Q数l参数都被转换成一个指针,要牢记这一点,因此如:(x)
{
printf("%d\n",sizeof(a));
}
昄应该打印指针大小4Q而非数组大小。另外,注意数组参数的地址跟数l参数第一个元素的地址q不相等Q在表达式中两者一_但是在函数调用中Q由于数l参数指针也是(f)时变量,因此两者的地址是不一L(fng)?br />
可以通过下列E序观察Q?br />
#include <stdlib.h>
void test1(char a[])
{
printf("&a=%x,&(a[0])=%x,&(a[1])=%x\n",&a,&(a[0]),&(a[1]));
}
void test2(char *b)
{
printf("&b=%x,&(b[0])=%x,&(b[1])=%x\n",&b,&(b[0]),&(b[1]));
}
int main(int argc, char *argv[])
{
char ga[]="hello";
printf("&ga=%x,&(ga[0])=%x,&(ga[1])=%x\n",&ga,&(ga[0]),&(ga[1]));
test1(ga);
test2(ga);
system("pause");
return 0;
}
二、指针跟数组什么时候不?br />
1、如果定义了一个数l,在其他文件对它进行声明也必须声明为数l,定义和声明必d配,指针也是如此?br />
2、指针始l是指针Q它l不可以写成数组。可以用下标形式讉K指针的时候,一般都是指针作为函数参数时Qƈ且你知道传递给函数的实际是一个数l?br />
3、数l名是不可改变的左|因此?br />
array=array2;
array++;
array--;
都将出错Q但是在函数内部Q?br />
void fun(int array[])
{
array=array2;
}
却可以,因ؓ(f)在函数内部array虽然被声明ؓ(f)数组实际上却是指针?br />
]]>
ACE_INET_Addr my_addr;
ACE_SOCK_Acceptor acceptor;
ACE_SOCK_Connector connector;
ACE_SOCK_Stream reader;
ACE_SOCK_Stream writer;
int result = 0;
# if defined (ACE_WIN32)
ACE_INET_Addr local_any (static_cast<u_short> (0), ACE_LOCALHOST);
# else
ACE_Addr local_any = ACE_Addr::sap_any;
# endif /* ACE_WIN32 */
// Bind listener to any port and then find out what the port was.
if (acceptor.open (local_any) == -1
|| acceptor.get_local_addr (my_addr) == -1)
result = -1;
else
{
ACE_INET_Addr sv_addr (my_addr.get_port_number (),
ACE_LOCALHOST);
// Establish a connection within the same process.
if (connector.connect (writer, sv_addr) == -1)
result = -1;
else if (acceptor.accept (reader) == -1)
{
writer.close ();
result = -1;
}
}
// Close down the acceptor endpoint since we don't need it anymore.
acceptor.close ();
在类unixq_是采用STREAMS道Q在一些遗留的unixq_上是socketpair()。ؓ(f)什么在win32上采用TCPq接的方式呢Q原因不是什么性能、资源问题,也不是因为windows道消耗的资源比tcp多,而是׃winsock的select函数Qjava nio的select在win32下是使用select实现的)是无法监管道事件的Q也是说无法将windows道加入到fd_set?Z做到可移植,才在win32上采用了TCPq接的方式来实现。这一点在blog上篇的新回复中已l有人提到?br />
]]>
2、根据READMEQ你需要下载三个依赖库Q?br />
wget http://www.kazmier.com/computer/snippet.el
wget http://www.webweavertech.com/ovidiu/emacs/find-recursive.txt
mv find-recursive.txt find-recursive.el
wget http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/misc/inf-ruby.el?view=co
mv inf-ruby.el\?view=co inf-ruby.el
3、将ruby源代码目录下?misc子目录中的emacs扩展文g拯?usr/share/emacs/site-lisp/目录下:(x)
4、在~/.emacsd两行代码Q加载emacs-rails
(require 'rails)
搞定Q看h挺强(zhn)的Q在菜单兰多了个ROR菜单Q需要熟(zhn)下快捷键?br />
]]>
安装是安装成功了Q但是仍然提C找不到openssl。还是决定从源码安装Q首先确保ubuntu安装了opensslQ?br />
sudo apt-get install openssl
sudo apt-get install libssl-dev
sudo apt-get install libssl0.9.8
然后q入ruby源码目录下的/ext/openssl
cd RUBY_SOURCE/ext/openssl
ruby extconf.rb
make
sudo make install
]]>
-U <num> 监听UDP端口Q默认是11211端口
-f <factor> q个参数很重要,用于讄chunk大小的递增因子。memcached的存储模型类g个二l数l:(x)slab->chunk->itemQ每个slab大小?MQslab中的chunk的大等于chunk的初始大乘以f^sidQf的sidơ方Q,其中sid是当前slab的idQchunk的默认大在1.1?字节Q在1.2?0字节。f是chunk的递增倍数Q在1.1固定?Q在1.2可通过-f参数讄Q默认ؓ(f)1.25。memcachd存储的item大小一般会(x)比存储的chunk size,那么有部分I间被浪费,Z量节省内存Q正设|?f参数显的非帔R要,通过计算量让chunk的大接q或者略大于存储的item的大?br />
-M q个参数?.1中就有了。这个参数用于在内存溢出的时候,止自动U除~存数据QLRUQ,替代的是q回一个error?br />
-s <size> 讄分配litem的key、value和flag的最字节数Q默认是48字节。根据你存储的item大小适当调整q个|可以更有效地利用内存?br />
-t <num> 讄处理h的线E数。这个参C在编译memcached启用U程时有效。这个参数通常讄的大等于CPU个数?br />
]]>
Table?/span>lua的主要——实际上Q也是唯一的——数据结构?/span>Table不仅在语a中,同时也在语言的实C扮演着重要角色?/span>Effort spent on a good implementation of tables is rewarded in the language,because tables are used for several internal tasks, with no qualms about performance。这有助于保持实现的y。相反的Q?/span>M其他数据l构的机制的~Z也ؓ(f)table的高效实现带来了很大压力
Lua中的table是关联数l,也就是可以用M值做索引Q除?/span>nilQ,也可以持有Q何倹{另外,table是动态的Q也是说当加进数据的时候它们将增长Q给q今不存在的域赋|而移除数据的时候将萎羃Q给域赋nil|?/span>
不像大多数其他脚本语aQ?/span>lua没有数组cd。数l被表示Z整数做键?/span>table。用table作ؓ(f)数组对于语言是有益的。主要的Q益处)显而易见:(x)luaq不需要操U表和数l的两套不同的运符。另外,E序员不用对两种实现做出艰难选择。在lua中实现稀疏数l是轻而易丄。例如,?/span>Perl里面Q如果你试去跑$a[1000000000]=1 q样的程序,你能跑出个内存溢出!Q?/span>you can run out of memoryQ,因ؓ(f)它触发了一?/span>10亿个元素的数l的创徏Q译注,Perl的哲学是Q去除不必要的限Ӟ。而等L(fng)luaE序 a={[1000000000]=1},Q只是)创徏了有一个单独的的表(而已Q?/span>
直到lua 4.0Q?/span>table都是作ؓ(f)hash表严格地实现Q所有的pair都被昑ּC存?/span>Lua5.0引入了一个新法来优化作为数l的tableQ它?yu)以整数为键?/span>pair不再是存储键而是优化成存储值在真正的数l中。更_地说Q在lua 5.0中,table被实Cؓ(f)一个合数据结构:(x)它们包括一?/span>hash部分和一个数l部分。图2展示了一个有"x"→ 9.3, 1 → 100,2 → 200, 3 → 300对子的表的一U可能结构。注意到数组部分在右边,q没有存储整数的key。这个划分仅仅是在一个低的实现层ơ进行的Q访?/span>table仍然是透明的,甚至在虚拟机内部Q访?/span>tableQ也是如此?/span>TableҎ(gu)内容自动q且动态地对两个部分进行适配Q数l部分试图从1?/span>n的相应地存储|兌非整数键或者整数键过数组范围的D存储?/span>hash部分?/span>
当一?/span>table需要增长时Q?/span>lua重新计算hash部分和数l部分的大小。Q一部分都可能是I的。重新计后的数l大是臛_是当前用的数组部分?/span>1?/span>n的一半情况下的最?/span>n|原文Q?/span>The computed
size of the array part is the largest n such that at least half the slots between 1 and n are in useQ(E疏数l时避免费I间Q,q至有一个(元素Q处?/span>n/2+1?/span>n的槽中(?/span>n?/span>2整除Ӟ避免n的这L(fng)数组大小Q。计完大小后,lua创徏?#8220;?#8221;的部分ƈ?#8220;?#8221;的部分的元素重新插入到的“?#8221;的部分。作Z个例子,假设a是一个空表;它的数组部分?/span>hash部分的大都?/span>0。当我们执行a[1]=vӞq个表需要增长到_容纳新的键?/span>Luaؓ(f)新的数组部分的大选择n=1Q带有一个项1→vQ?/span>hash部分仍然保持为空?/span>
q个混合的方案有两个优点。首先,讉K以整Cؓ(f)键的值加快了Q因Z再需要Q何的散列行ؓ(f)。其ơ,也是最重要的,数组部分占用的内存大概是数l部分存储在hash部分时的一半,因ؓ(f)key在数l中是隐式的Q译注:(x)也就是数l的下标Q而在hash部分却是昑ּ的。因而,当一?/span>table被用作数l的Ӟ它表现的像一个数l,只要整数键是密集。另外,不用?/span>hash部分付出M内存和时间上的惩|,因ؓ(f)它(译注Q?/span>hash部分Q甚至都不存在。相反的控制Q如?/span>table被用作关联数l而非一个数l,数组部分可能是I的。这些内存上的节省是比较重要的,因ؓ(f)luaE序l常创徏一些小?/span>tableQ例?/span>table被用来实现对象(ObjectQ(译注Q也是?/span>table来模仿对象,有点cMjavascript中的jsonQ?/span>
Hash部分采用Brent's
variation[3]的组合的铄发散表。这?/span>table的主要不变式是如果一个元素没有在它的主要位置上(也就?/span>hash值的原始位置Q,则冲H的元素在它自己的主要位|上。换句话_仅当两个元素有相同的主要位置Q也是在当?/span>table大小情况下的hash|时才有冲H的。没有二U冲H。正因ؓ(f)那样Q这?/span>table的加载因子可以是100%而没有性能上的损失。这部分不是很明白,附上原文Q?/span>
The hash part uses a mix of chained scatter table with
Brent's variation [3].
A main invariant of
these tables is that if an element is not in its main position
(i.e., the original
position given by its hash value), then the colliding element
is in its own main
position. In other words, there are collisions only when two
elements have the same
main position (i.e., the same hash values for that table
size). There are no
secondary collisions. Because of that, the load factor of these
tables can be 100% without performance penalties.
5、函数和闭包
?/span>lua~译一个函数的时候,它生一个模型(prototypeQ,包括了函数的虚拟机指令、常量|数字Q字W串字面量等Q和一些调试信息。运行的时候,无论何时lua执行一?/span>function…end表达式,它都创徏一个新的闭包。每个闭包都有一个引用指向相应的模型Q一个引用指向环境(environmentQ(一张查扑օ局变量的表Q译注:(x)指所谓环境就是这样一张表Q,和一l用来访问外?/span>local变量的指?/span>upvalue的引用?/span>
词法范围以及first-class函数的组合导致一个关于(如何Q访问外?/span>local变量的著名难题。考虑?/span>3中的例子。当add2被调用的时候,它的函数体(bodyQ部分引用了外部local变量x (函数参数?/span>lua里是local变量Q译注:(x)x是所谓的自由变量Q这里Ş成了闭包)。尽如此,?/span>add2被调用时Q生?/span>add2的函?/span>add已经q回。如果在栈中生成变量xQ(x在栈的)其栈槽将不复存在。(译注Q此处的意思应该是说如果在栈保存变?/span>xQ那么在调用add2的时候,add函数早已l返回,x也在add2调用前就不在栈里头了Q这是那个著名NQ?/span>
大多数过E语a通过限制词法范围Q例?/span>pythonQ,不提?/span>first-class函数Q例?/span>PascalQ,或者都两者都采用Q例?/span>c,译注Q也是?/span>c既不把函数当一{公民,也限制词法范_来回避这个问题。函数式语言没有那些限制。围l着非纯_函数语a比如Scheme?/span>ML的研I已l生了大量的关于闭包的~译技术的知识Q参?/span>[19, 1, 21]Q。尽如此,q些工作q没有尽力去限制~译器的复杂性。以优化?/span>Scheme~译?/span>Bigloo的控制流?/span>
析阶Dؓ(f)例,Q它的实玎ͼ?/span>lua实现?/span>10倍还大:(x)Bigloo
Lua使用了一个称?/span>upvalue的结构来实现闭包。Q何外?/span>local变量的访问都是通过一?/span>upvalue间接q行的?/span>Upvalue初始指向的是变量存活位置的栈槽(参见?/span>4的左半部分)。当变量Q?/span>xQ已l离开作用域(译注Q也是q里?/span>add函数q回ӞQ它?yu)pUdupvaluel构本n一个槽中(参见?/span>4的右半部分)。因为(对变量的Q访问是间接地通过upvaluel构中的一个指针进行的Q因此这个迁Ud于Q何写或者读该变量的代码都是透明的。不像它的内嵌函敎ͼ译注Q例子的add2Q它是指外部函数addQ,声明变量的函数访问该变量像讉K它的local变量一P(x)直接到栈?/span>
通过每个变量最多创Z?/span>upvaluel构q且在必要的时候复用它们,可变状态得以在闭包之间正确地共享。ؓ(f)了保证这一U束Q?/span>lual持一个链表,里面是一个栈里(?/span>4中的pending vars列表Q的所?/span>open upvalueQ所?/span>open upvalueQ是指仍然指向栈?/span>upvaluel构Q。当lua创徏一个新的闭包的时候,它遍历所有的外部local变量。对于每个(外部localQ变量,如果它在列表中找C?/span>open upvalueQ那么它?yu)复用这?/span>upvaluel构。否则,lua创Z个新?/span>upvalueq将它放入链表。注意到列表搜烦只是探测了少数几个节点,因ؓ(f)列表最多包含一个被内嵌函数使用?/span>local变量的项。当一?/span>closed
upvalue不再被Q何闭包引用的时候,它最后将被当作垃圑ƈ回收?/span>
一个函数允许访问一个不是它的直接外围函数的外部local变量Q只要(q个local变量Q是外部函数的(outer functionQ。在那种情况下,甚至在闭包被创徏的时候,Q外?/span>localQ变量可能就不在栈里了?/span>Lua使用扁^闭包Q?/span>flat
closuresQ解册U情?/span>[5]。通过扁^闭包Q一个函数无Z时去讉K一个不属于它的外围函数的外部变量,q个变量都将q入外围函数的闭包。从而当一个函数被实例化的时候,所有进入它闭包的变量要么在外围函数的栈里面Q要么在外围函数的闭包里?/span>
原文Qhttp://www.tecgraf.puc-rio.br/~lhf/ftp/doc/jucs05.pdf
译Qdennis zhuang (killme2008@gmail.com) http://www.aygfsteel.com/killme2008
转蝲h明出处,谢谢?/span>
摘要Q我们讨Zlua 5.0实现的主要新Ҏ(gu):(x)Z寄存器的虚拟机,优化表的新算法以便(表Q用作数l,闭包的实玎ͼ以及coroutinesQ译注:(x)协程Q?/span>
关键?/span>: compilers, virtual machines, hash tables, closures, coroutines
1. 介绍
Lua作ؓ(f)内部使用的开发工兯生于学术实验室中Q现在却已经被世界范围内许多工业U项目所采用Q广泛应用于游戏领域?/span>LuaZ么能获得q样q泛的应用呢Q我们认为答案就来源于我们的设计和实现目标上Q提供一U简单、高效、可UL和轻量的嵌入式脚本语言。这?/span>Lua?/span>1993q诞生以来我们一直追求的目标Qƈ在(语言的)演化q程中遵守?/span>q些Ҏ(gu),以及Lua一开始就被设计成嵌入大型应用的事实,才它在早期被工业界所接受?/span>
q泛的应用生了对(新的Q语a的特性的需求?/span>Lua的许多特性来自于工业需求和用户反馈的推动。重要的例如lua 5.0引入?/span>coroutines和即到来的Lua 5.1改进的垃圾收集实玎ͼq些Ҏ(gu)对于游戏(~程Q特别重要?/span>
在这论文中Q我们讨Zlua 5.0相比?/span>lua 4.0的主要新Ҏ(gu):(x)
Z寄存器的的虚拟机Q传l上Q绝大多数虚拟机的实际执行都是基于栈Q这个趋势开始于Pascal?/span>Pmachine,延箋C天的java虚拟机和微Y?/span>.net环境。目前,管对于Z寄存器的虚拟机的兴趣逐渐增多Q比?/span>Perl6计划中的新的虚拟机(ParrotQ将是基于寄存器的)Q但是就我们所知,lua 5.0是第一个被q泛使用的基于寄存器的虚拟机。我们将在第7部分描述q个虚拟机?/span>
优化表的新算法以便作为数l:(x) 不像其他脚本语言Q?/span>Luaq没有提供数l类型?/span>Lua使用整数索引的普通表来实现数l作为替代?/span>Lua 5.0使用了一个新的算法,可以表是否被作为数l用,q且可以自动关联着数字索引的值存储进一个真实的数组Q而不是将它们放进Hash表。在W?/span>4部分我们讨个算法?/span>
闭包的实玎ͼ(x)lua 5.0在词法层ơ上支持first-class
函数Q译注:(x)函CZ{公民)。这个机制导致一个著名的语言NQ用基于数l的栈来存储Ȁz记录?/span>Lua 使用了一个新办法来实现函数闭包,保存局部变量在Q基于数l)的栈(stack)上,当它们被内嵌函数引用而从作用域逸出的时候才它们{Ud?/span>(heap)上。闭包的实现在W?/span>5部分讨论?/span>
dcoroutinesQ?/span> lua 5.0语言引入?/span>coroutines。尽?/span>coroutines的实现较Zl,但ؓ(f)了完整性我们将在第6部分做个短的概况介绍?/span>
其他部分是ؓ(f)了讨论的完整性或者提供背景资料。在W?/span>2部分我们介绍?/span>lua的设计目标以及这个目标如何驱动实现的概况。在W?/span>3部分我们介绍?/span>lua是如何表C值的。尽就q个q程本n没有什么新意,但是ZQ理解)其他部分我们需要这些资料。最后,在第8部分Q我们介l了一个小型的基准试来得C些结论?/span>
2. lua设计和实现概?/span>
在介l部分提到过的,lua实现的主要目标是Q?/span>
单性:(x)我们探烦我们能提供的最单的语言Q以及实玎ͼq样的)语言的最单的C代码。这意味着Q需要)不会(x)偏离传统很远的拥有很语al构的简单语法?/span>
效率Q我们探索编译和执行luaE序的最快方法,q就意味着Q需要)一个高效的、聪明的一遍扫描编译器和一个高效的虚拟机?/span>
可移植性:(x)我们希望lua能跑在尽可能多的q_上。我们希望能在Q何地方不用修改地~译lua核心Q在M一个带有合适的lua解释器的q_上不用修改地q行luaE序。这意味着一个对可移植性特别关注的q净?/span>ANSI C的实玎ͼ例如避开C和标准库库中的陷qPq确保能?/span>c++方式q净地编译。我们追?/span>warning-free的编译(实现Q?/span>
嵌入性:(x)lua是一门扩展语aQ它被设计用来ؓ(f)大型E序提供脚本设施。这个以及其他目标就意味着一个简单ƈ且强大的C API实现Q但q样更多地依赖内徏?/span>Ccd?/span>
嵌入的低成本Q我们希望能Ҏ(gu)地将Luadq一个应用,而不?x)应用变的臃肿。这意味着Q需要)紧凑?/span>C代码和一个小?/span>Lua核心Q扩展将作ؓ(f)用户库来d?/span>
q些目标是有所权衡的。例如,lual常被用作数据描q语aQ用于保存和加蝲文gQ有时是非常大的数据?/span>(?/span>M字节?/span>luaE序不常?/span>)。这意味着我们需要一个快速的lua~译器。另一斚wQ我们想?/span>luaE序q行快速,q就意味着Q需要)一个可以ؓ(f)虚拟Z生优U代码的聪明的~译器。因此,LUA~译器的实现必须在这两种需求中Lq。尽如此,~译器还是不能太大,否则整个发行包变的臃ѝ目前编译器大约?/span>lua核心大小?/span>30%。在内存受限的应用中Q比如嵌入式pȝQ嵌入不带有~译器的Lua是可能的Q?/span>LuaE序被ȝ预编译,然后被一个小模块Q这个小模块也是快速的Q因为它加蝲的是二进制文Ӟ在运行时加蝲?/span>
Lua使用了一个手写的扫描器和一个手写的递归下降解释器。直?/span>3.0版本Q?/span>luaq在使用一?/span>YACC产生的解释器Q这在语a的语法不够稳定的时候很有h(hun)值的。然而,手写的解释器更小、更高效、更M以及完全可重入,也能提供更好的出错信息(error messageQ?/span>
Lua~译器没有用中间代码表C(译注Q也是不生成中间代码)。当解释一个程序的时候,它以“on-the-fly”的方式给虚拟机发出指令。不q,它会(x)q行一些优化。例如,它会(x)推迟像变量和帔Rq样的基本表辑ּ的代码生成。当它解释这L(fng)表达式的时候,没有产生M代码Q而是使用一U简单的l构来表C它们。所以,判断一个给定指令的操作数是帔Rq是变量以及它们的值直接应用在指o都变的非常容易,避免了不必要的和昂贵的移动?/span>
ZM地在许许多多不同?/span>C~译器和q_之间ULQ?/span>Lua不能使用许多解释器通常使用的技巧,例如direct threaded code [8, 16]。作为替代,它(译注Q指lua解释器)使用了标准的while-switch分发循环。此处的C代码看v来过于复杂,但是复杂性也是ؓ(f)了确保可UL性。当lua在许多不同的q_上(包括64位^台和一?/span>16位^収ͼ被很多不同的C~译器编译,lua实现的可UL性一直以来变的越来越E_了?/span>
我们认ؓ(f)我们已经辑ֈ我们的设计和实现目标了?/span>Lua是一门非常轻便的语言Q它能跑在Q何一个带?/span>ANSI C~译器的q_上,从嵌入式pȝ到大型机?/span>Lua实是轻量的:(x)例如Q它?/span>linuxq_上的独立解释器包括所有的标准库,占用的空间小?/span>150K;核心更是于100K?/span>lua是高效的Q独立的基准试表明lua是脚本语aQ解释的、动态类型的语言Q领域中最快的语言之一。主观上我们也认?/span>lua是一门简单的语言Q语法上cMPascalQ语义上cMSchemeQ译注:(x)Lisp的一U方aQ?/span>
3、值的表示
Lua是动态类型语aQ类型依附于D不是变量?/span>Lua?/span>8U基本类型:(x)nil, boolean, number, string, table, function,userdata, ?/span>thread?/span>Nil是一个标记类型,它只拥有一个g?/span>nil?/span>Boolean是通常?/span>true?/span>false?/span>Number是双_ֺ点敎ͼ对应?/span>C语言中的doublecdQ但?/span>float或?/span>long作ؓ(f)替代来编?/span>lua也很Ҏ(gu)Q不游?/span>consoles或者小机器都缺乏对double的硬件支持)?/span>String是有昑ּ大小的字节数l,因此可以存储L的二q制cdQ包括嵌入零?/span>Tablecd是兌的数l,可以用Q何值做索引Q除?/span>nilQ,也可以持有Q何倹{?/span>Function是依据与lua虚拟接的协议~写?/span>lua函数或?/span>C函数?/span>Userdata本质上是指向用户内存区块Q?/span>user memory blockQ的指针Q有两种风格Q重量,?/span>lua分配块ƈ?/span>GC回收Q轻量Q由用户分配和释放(内存Q块。最后,thread表示coroutines。所有类型的值都?/span>first-class|(x)我们可以它们作为全局变量、局部变量和table的域来存储,作ؓ(f)参数传递给函数Q作为函数的q回值等{?/span>
typedef struct { typedef union {
int t; GCObject
*gc;
Value v; void *p;
} TObject; lua_Number n;
int b;
} Value;
Figure 1: 带标{union表示lua?/span>
LuaDCZؓ(f)带标{union(tagged unions)Q也是pairs(t,v)Q其?/span>t是一个决定了?/span>vcd的整数型标签Q?/span>v是一个实Cluacd?/span>C语言?/span>unionl构?/span>Nil拥有一个单独的|译注Q也是nilQ?/span>Booleans?/span>numbers被实Cؓ(f)“拆箱?#8221;的|(x)v?/span>union中直接表C些类型的倹{这意味着unionQ译注:(x)指图中的ValueQ必L_的空间容U?/span>doubleQ类型)?/span>Strings,tables,
functions, threads, ?/span> userdatacd的值通过引用来实玎ͼ(x)v拥有指向实现q些cd的结构的指针。这些结构(译注Q指实现Strings,tables, functions, threads, ?/span> userdataq些cd的具体结构)׃n一个共同的headQ用来保存用于垃圾收集的信息。结构的剩下的部分专属于各自的类型?/span>
Figure1展示了一个实际的lua值的实现?/span>TObject是这个实现的主要l构体:(x)它表CZ上文描述的带标签的联合体Q?/span>tagged unionsQ?/span> (t,v)?/span>Value是实C值的unioncd。类?/span>nil的值没有显式表C在q个unioncd中是因ؓ(f)标签已经_标识它们。域n用来表示numberscdQ?/span>lua_Number默认?/span>doublecdQ。同P?/span>b是给booleanscd用的Q域p是给轻量U的userdatacd。而域gc是ؓ(f)?x)被垃圾回收的其他类型准备的Q?/span>(strings, tables, functions, 重量U?/span>userdata, ?/span>threads)?/span>
使用带标{union实现lua值的一个后果就是拷贝值的代h(hun)E微昂贵了一点:(x)在一台支?/span>64?/span>doublecd?/span>32位机器上Q?/span>TObject的大是12字节Q或?/span>16字节Q如?/span>double?/span>8字节寚w的话Q,因此拯一个值将需要拷?/span>3Q或?/span>4Q个机器字长。尽如此,惛_ANSI C中实C个更好的值的表示是困隄。一些动态类型语aQ例?/span>Smalltalk80的原始实玎ͼ在每个指针中使用多余的位来存储值的cd标签。这个技巧在l大多数机器上正常工作,q是因ؓ(f)一个指针的最后两个或者三个位׃寚wL0Q所以可以被用作他途。但是,q项技术既不是可移植的也无法在ANSI C中实玎ͼC 语言标准甚至都不保证指针适合M整数cdQ所以没有在指针上操作位的标准方法?/span>
减小值大的另一个观点就是持有显式标{,从而避免在union中放|一?/span>doublecd。例如,所有的numbercd可以表示为堆分配的对象,像String那样。(python使用了这Ҏ(gu)术,除了预先分配了一些小的整数|。尽如此,q样的表C方法将使语a变的非常~慢。作为选择Q整数的值可以表CZ“拆箱?#8221;的|直接存储?/span>union中,而Q点值放在堆中。这个办法将极大地增加所有算术运操作的实现复杂度?/span>
cM早期的解释型语言Q例?/span>Snobol [11] ?/span> Icon [10]Q?/span>lua在一?/span>hash表中“拘留”(internalizes)字符Ԍ(x)Q?/span>hash表)没有重复地持有每个字W串的单独拷贝。此外,String是不可变的:(x)一个字W串一旦被“拘留”Q将不能再被改变。字W串的哈希g据一个合了位和术q算的简单表辑ּ来计,囊括所有的位。当字符串被“拘留”Ӟhashg存(?/span>hash表)Q以支持更快的字W串比较和表索引。如果字W串太长的话Q?/span>hash函数q不?x)用到字W串的所有字节,q有利于快速地散列长字W串。避免处理长字符串带来的性能损失是重要的Q因为(q样的操作)?/span>lua中是很普遍的。例如,?/span>lua处理文g的时候经常将整个文g内容作ؓ(f)一个单独的长字W串d内存?/span>
一. 目的
本文旨在介绍如何安装OpenLDAPq且讄一个公司内部的集中化的邮g地址薄服务器供客
L(fng)查询?nbsp;
基本上,OpenLDAPgq应用在其它许多斚wQ象集中化的用户帐号验证服务?但邮件地址
薄查询是最常用的?nbsp;
? 安装
?a >www.openldap.org下蝲最新的openldap软g包,按照~译和安装的步骤Q依ơ运行:(x)
#tar cvfz openldap-stable-20010524.tgz
#cd openldap-2.0.11
#./configure
#make depend
#make
#make test
#make install
我的操作环境是redhat 6.1Q如果没有遇CQ何错误,最后默认安装LDAP后台E序slapd
到目?usr/local/libexec;配置文g在目?usr/local/etc/openldap/ q且攑U?
OpenLDAP工具
ldapadd,ldapdelete,ldapmodify,ldapmodrdn,ldappasswd,ldapsearch 在目?
/usr/local/bin,q行时数据库?usr/local/var/openldap-ldbm ?nbsp;
? 讄
1) 更改配置文g/usr/local/etc/openldap/slapd.conf
在include /usr/local/etc/openldap/schema/core.schemaq行后面加上下面的行Q?
包括所有的Ҏ(gu)?nbsp;
include /usr/local/etc/openldap/schema/corba.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
include /usr/local/etc/openldap/schema/java.schema
include /usr/local/etc/openldap/schema/krb5-kdc.schema
include /usr/local/etc/openldap/schema/misc.schema
include /usr/local/etc/openldap/schema/nadf.schema
include /usr/local/etc/openldap/schema/nis.schema
include /usr/local/etc/openldap/schema/openldap.schema
2) 在文件slapd.conf?ldbm database definitions"部分更改相应?
suffix,rootdn行如?nbsp;
database ldbm
suffix "o=yourdomain,c=us"
rootdn "cn=root,o=yourdomain,c=us"
rootpw secret
directory /usr/local/var/openldap-ldbm
有各U格式你可以用,q里我用的是o=yourdomain,c=us 说明你的公司域名和所在的?
家或地区
rootdn的格式安装后默认为cn=Manager,q里改ؓ(f)root完全是自q喜好,q样W合
Unix/Linux中rooth最高权限的传统?nbsp;
3) 现在可以启动slapd了,q行/usr/local/libexec/slapd ?nbsp;
可以考虑?usr/local/bin and /usr/local/libexec加到搜烦路径中,卛_?
/etc/profile
中的PATH?
PATH="$PATH:/usr/X11R6/bin:/usr/local/bin:/usr/local/libexec"
q样下次d后只需键入 slapd ?nbsp;
4) 试ldap server是否正常工作?nbsp;
q行下面的命令检查是否有相应的输出?nbsp;
#ldapsearch -x -b 'o=yourdomain,c=us' '(objectclass=*)'
5) ~辑.ldif文本文gQ用ldapaddd记录q入LDAP数据库?nbsp;
文g内容如下Q?nbsp;
dn: o=yourdomain,c=us
objectclass: dcobject
objectclass: organization
o: yourdomain
dc: yourdomain
dn: cn=Jephe Wu,o=yourdomain,c=us
objectclass: inetorgperson
cn: Jephe Wu
sn: Wu
mail: jephe_wu@yourdomain.com
......more users......
依次cLQ添加每个h的记录进入该文g中,注意对象cd inetorgperson 臛_必须?
有cn和sn
,q里我们用cn,sn,mail三项定义,q对我们的邮件地址薄功能来说已l够。你q可?
定义?nbsp;
mobile, homephone,pager......{等?nbsp;
然后用下面的命od上面?ldif文gq入LDAP数据?nbsp;
#ldapadd -x -D "cn=root,o=yourdomain,c=us" -w secret -f
"yourldiffilename"
注:(x)上面的文件的W一部分"dn: o=yourdomain,c=us"是必ȝQ否则不能添加数据?nbsp;
用你的公司的域名替换上面?yourdomain"?nbsp;
6) 讄Outlook Express, 允许用LDAP服务器查询邮件地址?nbsp;
"工具/帐号/d--目录服务"Q填入你的服务器的IP地址或者主机全U域名,在下一个屏
q中选yes以允许用目录服务来查询地址Q最后在"目录服务"栏中选中刚才讄的项目击
“属?高",?搜烦?中填?nbsp;
"o=yourdomain,c=us" ?nbsp;
Netscapeh据上面的信息讄相应的选项?nbsp;
? 常见使用问题
1) 能启动slapd 没有问题Q但不能d数据库,q行ldapaddd时出?"ldap_bind:
cannot contact LDAP Server" ?nbsp;
{? 最可能的原因是?etc/hosts中没?27.0.0.1 localhost目?nbsp;
2) 注意查询序: 如果在Outlook Express的地址薄中有内容,则检查地址时地址薄优
先,如果在本地地址薄中找不到相应记录,然后再查询LDAP服务器?nbsp;
3) 用下面的命o信客户端与LDAP服务器有通讯,在服务器q行下面的命令,然后在OE?
试查地址Q你会(x)得到查询LDAP数据库的q接q程的输出?nbsp;