﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-&lt;font color="#ff8000"&gt;&amp;nbsp&amp;nbsp&amp;nbspC++&amp;nbsp技术中心&lt;/font&gt;-随笔分类-其他编程</title><link>http://www.cppblog.com/API/category/20757.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 07 May 2020 14:46:01 GMT</lastBuildDate><pubDate>Thu, 07 May 2020 14:46:01 GMT</pubDate><ttl>60</ttl><item><title>origin游戏服务器引擎介绍</title><link>http://www.cppblog.com/API/archive/2020/05/07/217287.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Thu, 07 May 2020 08:06:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2020/05/07/217287.html</guid><wfw:comment>http://www.cppblog.com/API/comments/217287.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2020/05/07/217287.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/217287.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/217287.html</trackback:ping><description><![CDATA[<div>origin 游戏服务器引擎简介</div><div>==================</div><div></div><div></div><div>origin 是一个由 Go 语言（golang）编写的分布式开源游戏服务器引擎。origin适用于各类游戏服务器的开发，包括 H5（HTML5）游戏服务器。</div><div></div><div>origin 解决的问题：</div><div>* origin总体设计如go语言设计一样，总是尽可能的提供简洁和易用的模式，快速开发。</div><div>* 能够根据业务需求快速并灵活的制定服务器架构。</div><div>* 利用多核优势，将不同的service配置到不同的node，并能高效的协同工作。</div><div>* 将整个引擎抽象三大对象，node,service,module。通过统一的组合模型管理游戏中各功能模块的关系。</div><div>* 有丰富并健壮的工具库。</div><div></div><div>Hello world!</div><div>---------------</div><div>下面我们来一步步的建立origin服务器,先下载[origin引擎](https://github.com/duanhf2012/origin "origin引擎"),或者使用如下命令：</div><div>```go</div><div>go get -v -u&nbsp; github.com/duanhf2012/origin</div><div>```</div><div>于是下载到GOPATH环境目录中,在src中加入main.go,内容如下：</div><div>```go</div><div>package main</div><div></div><div>import (</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div>)</div><div></div><div>func main() {</div><div><span style="white-space:pre">	</span>node.Start()</div><div>}</div><div>```</div><div>一个origin进程需要创建一个node对象,Start开始运行。您也可以直接下载origin引擎示例:</div><div>```</div><div>go get -v -u github.com/duanhf2012/originserver</div><div>```</div><div>本文所有的说明都是基于该示例为主。</div><div></div><div>origin引擎三大对象关系</div><div>---------------</div><div>* Node:&nbsp; &nbsp;可以认为每一个Node代表着一个origin进程</div><div>* Service:一个独立的服务可以认为是一个大的功能模块，他是Node的子集，创建完成并安装Node对象中。服务可以支持对外部RPC等功能。</div><div>* Module: 这是origin最小对象单元，强烈建议所有的业务模块都划分成各个小的Module组合，origin引擎将监控所有服务与Module运行状态，例如可以监控它们的慢处理和死循环函数。Module可以建立树状关系。Service本身也是Module的类型。</div><div></div><div>origin集群核心配置文件在config的cluster目录下，在cluster下有子网目录，如github.com/duanhf2012/originserver的config/cluster目录下有subnet目录，表示子网名为subnet，可以新加多个子网的目录配置。子网与子网间是隔离的，后续将支持子网间通信规则，origin集群配置以子网的模式配置，在每个子网下配置多个Node服务器,子网在应对复杂的系统时可以应用到各个子系统，方便每个子系统的隔离。在示例的subnet目录中有cluster.json与service.json配置：</div><div></div><div>cluster.json如下：</div><div>---------------</div><div>```</div><div>{</div><div>&nbsp; &nbsp; "NodeList":[</div><div>&nbsp; &nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "NodeId": 1,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ListenAddr":"127.0.0.1:8001",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "NodeName": "Node_Test1",</div><div><span style="white-space:pre">		</span>&nbsp; "remark":"//以_打头的，表示只在本机进程，不对整个子网开发",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ServiceList": ["TestService1","TestService2","TestServiceCall","GateService","_TcpService","HttpService","WSService"]</div><div>&nbsp; &nbsp; &nbsp; &nbsp; },</div><div><span style="white-space:pre">		</span> {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "NodeId": 2,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ListenAddr":"127.0.0.1:8002",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "NodeName": "Node_Test1",</div><div><span style="white-space:pre">		</span>&nbsp; "remark":"//以_打头的，表示只在本机进程，不对整个子网开发",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ServiceList": ["TestService1","TestService2","TestServiceCall","GateService","TcpService","HttpService","WSService"]</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; ]</div><div>```</div><div>---------------</div><div>以上配置了两个结点服务器程序:</div><div>* NodeId: 表示origin程序的结点Id标识，不允许重复。</div><div>* ListenAddr:Rpc通信服务的监听地址</div><div>* NodeName:结点名称</div><div>* remark:备注，可选项</div><div>* ServiceList:该Node将安装的服务列表</div><div>---------------</div><div></div><div>在启动程序命令program start nodeid=1中nodeid就是根据该配置装载服务。</div><div>service.json如下：</div><div>---------------</div><div>```</div><div>{</div><div>&nbsp; "Service":{</div><div><span style="white-space:pre">	</span>&nbsp; "HttpService":{</div><div><span style="white-space:pre">		</span>"ListenAddr":"0.0.0.0:9402",</div><div><span style="white-space:pre">		</span>"ReadTimeout":10000,</div><div><span style="white-space:pre">		</span>"WriteTimeout":10000,</div><div><span style="white-space:pre">		</span>"ProcessTimeout":10000,</div><div><span style="white-space:pre">		</span>"CAFile":[</div><div><span style="white-space:pre">		</span>{</div><div><span style="white-space:pre">			</span>"Certfile":"",</div><div><span style="white-space:pre">			</span>"Keyfile":""</div><div><span style="white-space:pre">		</span>}</div><div><span style="white-space:pre">		</span>]</div><div><span style="white-space:pre">		</span></div><div><span style="white-space:pre">	</span>&nbsp; },</div><div><span style="white-space:pre">	</span>&nbsp; "TcpService":{</div><div><span style="white-space:pre">		</span>"ListenAddr":"0.0.0.0:9030",</div><div><span style="white-space:pre">		</span>"MaxConnNum":3000,</div><div><span style="white-space:pre">		</span>"PendingWriteNum":10000,</div><div><span style="white-space:pre">		</span>"LittleEndian":false,</div><div><span style="white-space:pre">		</span>"MinMsgLen":4,</div><div><span style="white-space:pre">		</span>"MaxMsgLen":65535</div><div><span style="white-space:pre">	</span>&nbsp; },</div><div><span style="white-space:pre">	</span>&nbsp; "WSService":{</div><div><span style="white-space:pre">		</span>"ListenAddr":"0.0.0.0:9031",</div><div><span style="white-space:pre">		</span>"MaxConnNum":3000,</div><div><span style="white-space:pre">		</span>"PendingWriteNum":10000,</div><div><span style="white-space:pre">		</span>"MaxMsgLen":65535</div><div><span style="white-space:pre">	</span>&nbsp; }&nbsp;&nbsp;</div><div>&nbsp; },</div><div>&nbsp; "NodeService":[</div><div>&nbsp; &nbsp;{</div><div>&nbsp; &nbsp; &nbsp; "NodeId":1,</div><div><span style="white-space:pre">	</span>&nbsp; "TcpService":{</div><div><span style="white-space:pre">		</span>"ListenAddr":"0.0.0.0:9830",</div><div><span style="white-space:pre">		</span>"MaxConnNum":3000,</div><div><span style="white-space:pre">		</span>"PendingWriteNum":10000,</div><div><span style="white-space:pre">		</span>"LittleEndian":false,</div><div><span style="white-space:pre">		</span>"MinMsgLen":4,</div><div><span style="white-space:pre">		</span>"MaxMsgLen":65535</div><div><span style="white-space:pre">	</span>&nbsp; },</div><div><span style="white-space:pre">	</span>&nbsp; "WSService":{</div><div><span style="white-space:pre">		</span>"ListenAddr":"0.0.0.0:9031",</div><div><span style="white-space:pre">		</span>"MaxConnNum":3000,</div><div><span style="white-space:pre">		</span>"PendingWriteNum":10000,</div><div><span style="white-space:pre">		</span>"MaxMsgLen":65535</div><div><span style="white-space:pre">	</span>&nbsp; }&nbsp;&nbsp;</div><div>&nbsp; &nbsp;},</div><div>&nbsp; &nbsp;{</div><div>&nbsp; &nbsp; &nbsp; "NodeId":2,</div><div><span style="white-space:pre">	</span>&nbsp; "TcpService":{</div><div><span style="white-space:pre">		</span>"ListenAddr":"0.0.0.0:9030",</div><div><span style="white-space:pre">		</span>"MaxConnNum":3000,</div><div><span style="white-space:pre">		</span>"PendingWriteNum":10000,</div><div><span style="white-space:pre">		</span>"LittleEndian":false,</div><div><span style="white-space:pre">		</span>"MinMsgLen":4,</div><div><span style="white-space:pre">		</span>"MaxMsgLen":65535</div><div><span style="white-space:pre">	</span>&nbsp; },</div><div><span style="white-space:pre">	</span>&nbsp; "WSService":{</div><div><span style="white-space:pre">		</span>"ListenAddr":"0.0.0.0:9031",</div><div><span style="white-space:pre">		</span>"MaxConnNum":3000,</div><div><span style="white-space:pre">		</span>"PendingWriteNum":10000,</div><div><span style="white-space:pre">		</span>"MaxMsgLen":65535</div><div><span style="white-space:pre">	</span>&nbsp; }&nbsp;&nbsp;</div><div>&nbsp; &nbsp;}</div><div>&nbsp; ]</div><div>&nbsp;</div><div>}</div><div>```</div><div></div><div>---------------</div><div>以上配置分为两个部分：Service与NodeService，NodeService中配置的对应结点中服务的配置，如果启动程序中根据nodeid查找该域的对应的服务，如果找不到时，从Service公共部分查找。</div><div></div><div>**HttpService配置**</div><div>* ListenAddr:Http监听地址</div><div>* ReadTimeout:读网络超时毫秒</div><div>* WriteTimeout:写网络超时毫秒</div><div>* ProcessTimeout: 处理超时毫秒</div><div>* CAFile: 证书文件，如果您的服务器通过web服务器代理配置https可以忽略该配置</div><div></div><div>**TcpService配置**</div><div>* ListenAddr: 监听地址</div><div>* MaxConnNum: 允许最大连接数</div><div>* PendingWriteNum：发送网络队列最大数量</div><div>* LittleEndian:是否小端</div><div>* MinMsgLen:包最小长度</div><div>* MaxMsgLen:包最大长度</div><div></div><div>**WSService配置**</div><div>* ListenAddr: 监听地址</div><div>* MaxConnNum: 允许最大连接数</div><div>* PendingWriteNum：发送网络队列最大数量</div><div>* MaxMsgLen:包最大长度</div><div>---------------</div><div></div><div></div><div></div><div></div><div>第一章：origin基础:</div><div>---------------</div><div>查看github.com/duanhf2012/originserver中的simple_service中新建两个服务，分别是TestService1.go与CTestService2.go。</div><div></div><div>simple_service/TestService1.go如下：</div><div>```</div><div>package simple_service</div><div></div><div>import (</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/service"</div><div>)</div><div></div><div>//模块加载时自动安装TestService1服务</div><div>func init(){</div><div><span style="white-space:pre">	</span>node.Setup(&amp;TestService1{})</div><div>}</div><div></div><div>//新建自定义服务TestService1</div><div>type TestService1 struct {</div><div></div><div><span style="white-space:pre">	</span>//所有的自定义服务必需加入service.Service基服务</div><div><span style="white-space:pre">	</span>//那么该自定义服务将有各种功能特性</div><div><span style="white-space:pre">	</span>//例如: Rpc,事件驱动,定时器等</div><div><span style="white-space:pre">	</span>service.Service</div><div>}</div><div></div><div>//服务初始化函数，在安装服务时，服务将自动调用OnInit函数</div><div>func (slf *TestService1) OnInit() error {</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div></div><div>```</div><div>simple_service/TestService2.go如下：</div><div>```</div><div>import (</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/service"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre">	</span>node.Setup(&amp;TestService2{})</div><div>}</div><div></div><div>type TestService2 struct {</div><div><span style="white-space:pre">	</span>service.Service</div><div>}</div><div></div><div>func (slf *TestService2) OnInit() error {</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div></div><div>```</div><div></div><div>* main.go运行代码</div><div></div><div>```go</div><div>package main</div><div></div><div>import (</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre">	</span>//导入simple_service模块</div><div><span style="white-space:pre">	</span>_"orginserver/simple_service"</div><div>)</div><div></div><div>func main(){</div><div><span style="white-space:pre">	</span>node.Start()</div><div>}</div><div></div><div>```</div><div></div><div>* config/cluster/subnet/cluster.json如下：</div><div>```</div><div>{</div><div>&nbsp; &nbsp; "NodeList":[</div><div>&nbsp; &nbsp; &nbsp; &nbsp; {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "NodeId": 1,</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ListenAddr":"127.0.0.1:8001",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "NodeName": "Node_Test1",</div><div><span style="white-space:pre">		</span>&nbsp; "remark":"//以_打头的，表示只在本机进程，不对整个子网开发",</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "ServiceList": ["TestService1","TestService2"]</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; ]</div><div>}</div><div>```</div><div></div><div>编译后运行结果如下：</div><div>```</div><div>#originserver start nodeid=1</div><div>TestService1 OnInit.</div><div>TestService2 OnInit.</div><div>```</div><div></div><div>第二章：Service中常用功能:</div><div>---------------</div><div></div><div>定时器:</div><div>---------------</div><div>在开发中最常用的功能有定时任务，origin提供两种定时方式：</div><div></div><div>一种AfterFunc函数，可以间隔一定时间触发回调，参照simple_service/TestService2.go,实现如下：</div><div>```</div><div>func (slf *TestService2) OnInit() error {</div><div><span style="white-space:pre">	</span>fmt.Printf("TestService2 OnInit.\n")</div><div><span style="white-space:pre">	</span>slf.AfterFunc(time.Second*1,slf.OnSecondTick)</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>func (slf *TestService2) OnSecondTick(){</div><div><span style="white-space:pre">	</span>fmt.Printf("tick.\n")</div><div><span style="white-space:pre">	</span>slf.AfterFunc(time.Second*1,slf.OnSecondTick)</div><div>}</div><div>```</div><div>此时日志可以看到每隔1秒钟会print一次"tick."，如果下次还需要触发，需要重新设置定时器</div><div></div><div></div><div>另一种方式是类似Linux系统的crontab命令，使用如下：</div><div>```</div><div></div><div>func (slf *TestService2) OnInit() error {</div><div><span style="white-space:pre">	</span>fmt.Printf("TestService2 OnInit.\n")</div><div></div><div><span style="white-space:pre">	</span>//crontab模式定时触发</div><div><span style="white-space:pre">	</span>//NewCronExpr的参数分别代表:Seconds Minutes Hours DayOfMonth Month DayOfWeek</div><div><span style="white-space:pre">	</span>//以下为每换分钟时触发</div><div><span style="white-space:pre">	</span>cron,_:=timer.NewCronExpr("0 * * * * *")</div><div><span style="white-space:pre">	</span>slf.CronFunc(cron,slf.OnCron)</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div></div><div>func (slf *TestService2) OnCron(){</div><div><span style="white-space:pre">	</span>fmt.Printf(":A minute passed!\n")</div><div>}</div><div>```</div><div>以上运行结果每换分钟时打印:A minute passed!</div><div></div><div></div><div>打开多协程模式:</div><div>---------------</div><div>在origin引擎设计中，所有的服务是单协程模式，这样在编写逻辑代码时，不用考虑线程安全问题。极大的减少开发难度，但某些开发场景下不用考虑这个问题，而且需要并发执行的情况，比如，某服务只处理数据库操作控制，而数据库处理中发生阻塞等待的问题，因为一个协程，该服务接受的数据库操作只能是一个</div><div>一个的排队处理，效率过低。于是可以打开此模式指定处理协程数，代码如下：</div><div>```</div><div>func (slf *TestService1) OnInit() error {</div><div><span style="white-space:pre">	</span>fmt.Printf("TestService1 OnInit.\n")</div><div><span style="white-space:pre">	</span></div><div><span style="white-space:pre">	</span>//打开多线程处理模式，10个协程并发处理</div><div><span style="white-space:pre">	</span>slf.SetGoRouterNum(10)</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div>```</div><div>为了</div><div></div><div></div><div>性能监控功能:</div><div>---------------</div><div>我们在开发一个大型的系统时，经常由于一些代码质量的原因，产生处理过慢或者死循环的产生，该功能可以被监测到。使用方法如下：</div><div></div><div>```</div><div>func (slf *TestService1) OnInit() error {</div><div><span style="white-space:pre">	</span>fmt.Printf("TestService1 OnInit.\n")</div><div><span style="white-space:pre">	</span>//打开性能分析工具</div><div><span style="white-space:pre">	</span>slf.OpenProfiler()</div><div><span style="white-space:pre">	</span>//监控超过1秒的慢处理</div><div><span style="white-space:pre">	</span>slf.GetProfiler().SetOverTime(time.Second*1)</div><div><span style="white-space:pre">	</span>//监控超过10秒的超慢处理，您可以用它来定位是否存在死循环</div><div><span style="white-space:pre">	</span>//比如以下设置10秒，我的应用中是不会发生超过10秒的一次函数调用</div><div><span style="white-space:pre">	</span>//所以设置为10秒。</div><div><span style="white-space:pre">	</span>slf.GetProfiler().SetMaxOverTime(time.Second*10)</div><div></div><div><span style="white-space:pre">	</span>slf.AfterFunc(time.Second*2,slf.Loop)</div><div><span style="white-space:pre">	</span>//打开多线程处理模式，10个协程并发处理</div><div><span style="white-space:pre">	</span>//slf.SetGoRouterNum(10)</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>func (slf *TestService1) Loop(){</div><div><span style="white-space:pre">	</span>for {</div><div><span style="white-space:pre">		</span>time.Sleep(time.Second*1)</div><div><span style="white-space:pre">	</span>}</div><div>}</div><div></div><div></div><div>func main(){</div><div><span style="white-space:pre">	</span>//打开性能分析报告功能，并设置10秒汇报一次</div><div><span style="white-space:pre">	</span>node.OpenProfilerReport(time.Second*10)</div><div><span style="white-space:pre">	</span>node.Start()</div><div>}</div><div></div><div>```</div><div>上面通过GetProfiler().SetOverTime与slf.GetProfiler().SetMaxOverTimer设置监控时间</div><div>并在main.go中，打开了性能报告器，以每10秒汇报一次，因为上面的例子中，定时器是有死循环，所以可以得到以下报告：</div><div></div><div>2020/04/22 17:53:30 profiler.go:179: [release] Profiler report tag TestService1:</div><div>process count 0,take time 0 Milliseconds,average 0 Milliseconds/per.</div><div>too slow process:Timer_orginserver/simple_service.(*TestService1).Loop-fm is take 38003 Milliseconds</div><div>直接帮助找到TestService1服务中的Loop函数</div><div></div><div></div><div></div><div>第三章：Module使用:</div><div>---------------</div><div></div><div>Module创建与销毁:</div><div>---------------</div><div>可以认为Service就是一种Module，它有Module所有的功能。在示例代码中可以参考originserver/simple_module/TestService3.go。</div><div>```</div><div>package simple_module</div><div></div><div>import (</div><div><span style="white-space:pre">	</span>"fmt"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/service"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre">	</span>node.Setup(&amp;TestService3{})</div><div>}</div><div></div><div>type TestService3 struct {</div><div><span style="white-space:pre">	</span>service.Service</div><div>}</div><div></div><div>type Module1 struct {</div><div><span style="white-space:pre">	</span>service.Module</div><div>}</div><div></div><div>type Module2 struct {</div><div><span style="white-space:pre">	</span>service.Module</div><div>}</div><div></div><div>func (slf *Module1) OnInit()error{</div><div><span style="white-space:pre">	</span>fmt.Printf("Module1 OnInit.\n")</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>func (slf *Module1) OnRelease(){</div><div><span style="white-space:pre">	</span>fmt.Printf("Module1 Release.\n")</div><div>}</div><div></div><div>func (slf *Module2) OnInit()error{</div><div><span style="white-space:pre">	</span>fmt.Printf("Module2 OnInit.\n")</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>func (slf *Module2) OnRelease(){</div><div><span style="white-space:pre">	</span>fmt.Printf("Module2 Release.\n")</div><div>}</div><div></div><div></div><div>func (slf *TestService3) OnInit() error {</div><div><span style="white-space:pre">	</span>//新建两个Module对象</div><div><span style="white-space:pre">	</span>module1 := &amp;Module1{}</div><div><span style="white-space:pre">	</span>module2 := &amp;Module2{}</div><div><span style="white-space:pre">	</span>//将module1添加到服务中</div><div><span style="white-space:pre">	</span>module1Id,_ := slf.AddModule(module1)</div><div><span style="white-space:pre">	</span>//在module1中添加module2模块</div><div><span style="white-space:pre">	</span>module1.AddModule(module2)</div><div><span style="white-space:pre">	</span>fmt.Printf("module1 id is %d, module2 id is %d",module1Id,module2.GetModuleId())</div><div></div><div><span style="white-space:pre">	</span>//释放模块module1</div><div><span style="white-space:pre">	</span>slf.ReleaseModule(module1Id)</div><div><span style="white-space:pre">	</span>fmt.Printf("xxxxxxxxxxx")</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>```</div><div>在OnInit中创建了一条线型的模块关系TestService3-&gt;module1-&gt;module2，调用AddModule后会返回Module的Id，自动生成的Id从10e17开始,内部的id，您可以自己设置Id。当调用ReleaseModule释放时module1时，同样会将module2释放。会自动调用OnRelease函数，日志顺序如下：</div><div>```</div><div>Module1 OnInit.</div><div>Module2 OnInit.</div><div>module1 id is 100000000000000001, module2 id is 100000000000000002</div><div>Module2 Release.</div><div>Module1 Release.</div><div>```</div><div>在Module中同样可以使用定时器功能，请参照第二章节的定时器部分。</div><div></div><div></div><div>第四章：事件使用</div><div>---------------</div><div>事件是origin中一个重要的组成部分，可以在同一个node中的service与service或者与module之间进行事件通知。系统内置的几个服务，如：TcpService/HttpService等都是通过事件功能实现。他也是一个典型的观察者设计模型。在event中有两个类型的interface，一个是event.IEventProcessor它提供注册与卸载功能，另一个是event.IEventHandler提供消息广播等功能。</div><div></div><div>在目录simple_event/TestService4.go中</div><div>```</div><div>package simple_event</div><div></div><div>import (</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/event"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/service"</div><div><span style="white-space:pre">	</span>"time"</div><div>)</div><div></div><div>const (</div><div><span style="white-space:pre">	</span>//自定义事件类型，必需从event.Sys_Event_User_Define开始</div><div><span style="white-space:pre">	</span>//event.Sys_Event_User_Define以内给系统预留</div><div><span style="white-space:pre">	</span>EVENT1 event.EventType =event.Sys_Event_User_Define+1</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre">	</span>node.Setup(&amp;TestService4{})</div><div>}</div><div></div><div>type TestService4 struct {</div><div><span style="white-space:pre">	</span>service.Service</div><div>}</div><div></div><div>func (slf *TestService4) OnInit() error {</div><div><span style="white-space:pre">	</span>//10秒后触发广播事件</div><div><span style="white-space:pre">	</span>slf.AfterFunc(time.Second*10,slf.TriggerEvent)</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>func (slf *TestService4) TriggerEvent(){</div><div><span style="white-space:pre">	</span>//广播事件，传入event.Event对象，类型为EVENT1,Data可以自定义任何数据</div><div><span style="white-space:pre">	</span>//这样，所有监听者都可以收到该事件</div><div><span style="white-space:pre">	</span>slf.GetEventHandler().NotifyEvent(&amp;event.Event{</div><div><span style="white-space:pre">		</span>Type: EVENT1,</div><div><span style="white-space:pre">		</span>Data: "event data.",</div><div><span style="white-space:pre">	</span>})</div><div>}</div><div></div><div></div><div>```</div><div></div><div>在目录simple_event/TestService5.go中</div><div>```</div><div>package simple_event</div><div></div><div>import (</div><div><span style="white-space:pre">	</span>"fmt"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/event"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/service"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre">	</span>node.Setup(&amp;TestService5{})</div><div>}</div><div></div><div>type TestService5 struct {</div><div><span style="white-space:pre">	</span>service.Service</div><div>}</div><div></div><div>type TestModule struct {</div><div><span style="white-space:pre">	</span>service.Module</div><div>}</div><div></div><div>func (slf *TestModule) OnInit() error{</div><div><span style="white-space:pre">	</span>//在当前node中查找TestService4</div><div><span style="white-space:pre">	</span>pService := node.GetService("TestService4")</div><div></div><div><span style="white-space:pre">	</span>//在TestModule中，往TestService4中注册EVENT1类型事件监听</div><div><span style="white-space:pre">	</span>pService.(*TestService4).GetEventProcessor().RegEventReciverFunc(EVENT1,slf.GetEventHandler(),slf.OnModuleEvent)</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>func (slf *TestModule) OnModuleEvent(ev *event.Event){</div><div><span style="white-space:pre">	</span>fmt.Printf("OnModuleEvent type :%d data:%+v\n",ev.Type,ev.Data)</div><div>}</div><div></div><div></div><div>//服务初始化函数，在安装服务时，服务将自动调用OnInit函数</div><div>func (slf *TestService5) OnInit() error {</div><div><span style="white-space:pre">	</span>//通过服务名获取服务对象</div><div><span style="white-space:pre">	</span>pService := node.GetService("TestService4")</div><div></div><div><span style="white-space:pre">	</span>////在TestModule中，往TestService4中注册EVENT1类型事件监听</div><div><span style="white-space:pre">	</span>pService.(*TestService4).GetEventProcessor().RegEventReciverFunc(EVENT1,slf.GetEventHandler(),slf.OnServiceEvent)</div><div><span style="white-space:pre">	</span>slf.AddModule(&amp;TestModule{})</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>func (slf *TestService5) OnServiceEvent(ev *event.Event){</div><div><span style="white-space:pre">	</span>fmt.Printf("OnServiceEvent type :%d data:%+v\n",ev.Type,ev.Data)</div><div>}</div><div></div><div></div><div>```</div><div>程序运行10秒后，调用slf.TriggerEvent函数广播事件，于是在TestService5中会收到</div><div>```</div><div>OnServiceEvent type :1001 data:event data.</div><div>OnModuleEvent type :1001 data:event data.</div><div>```</div><div>在上面的TestModule中监听的事情，当这个Module被Release时监听会自动卸载。</div><div></div><div>第五章：RPC使用</div><div>---------------</div><div>RPC是service与service间通信的重要方式，它允许跨进程node互相访问，当然也可以指定nodeid进行调用。如下示例：</div><div></div><div>simple_rpc/TestService6.go文件如下：</div><div>```</div><div>package simple_rpc</div><div></div><div>import (</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/service"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre">	</span>node.Setup(&amp;TestService6{})</div><div>}</div><div></div><div>type TestService6 struct {</div><div><span style="white-space:pre">	</span>service.Service</div><div>}</div><div></div><div>func (slf *TestService6) OnInit() error {</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>type InputData struct {</div><div><span style="white-space:pre">	</span>A int</div><div><span style="white-space:pre">	</span>B int</div><div>}</div><div></div><div>func (slf *TestService6) RPC_Sum(input *InputData,output *int) error{</div><div><span style="white-space:pre">	</span>*output = input.A+input.B</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>```</div><div></div><div>simple_rpc/TestService7.go文件如下：</div><div>```</div><div>package simple_rpc</div><div></div><div>import (</div><div><span style="white-space:pre">	</span>"fmt"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/service"</div><div><span style="white-space:pre">	</span>"time"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre">	</span>node.Setup(&amp;TestService7{})</div><div>}</div><div></div><div>type TestService7 struct {</div><div><span style="white-space:pre">	</span>service.Service</div><div>}</div><div></div><div>func (slf *TestService7) OnInit() error {</div><div><span style="white-space:pre">	</span>slf.AfterFunc(time.Second*2,slf.CallTest)</div><div><span style="white-space:pre">	</span>slf.AfterFunc(time.Second*2,slf.AsyncCallTest)</div><div><span style="white-space:pre">	</span>slf.AfterFunc(time.Second*2,slf.GoTest)</div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>func (slf *TestService7) CallTest(){</div><div><span style="white-space:pre">	</span>var input InputData</div><div><span style="white-space:pre">	</span>input.A = 300</div><div><span style="white-space:pre">	</span>input.B = 600</div><div><span style="white-space:pre">	</span>var output int</div><div></div><div><span style="white-space:pre">	</span>//同步调用其他服务的rpc,input为传入的rpc,output为输出参数</div><div><span style="white-space:pre">	</span>err := slf.Call("TestService6.RPC_Sum",&amp;input,&amp;output)</div><div><span style="white-space:pre">	</span>if err != nil {</div><div><span style="white-space:pre">		</span>fmt.Printf("Call error :%+v\n",err)</div><div><span style="white-space:pre">	</span>}else{</div><div><span style="white-space:pre">		</span>fmt.Printf("Call output %d\n",output)</div><div><span style="white-space:pre">	</span>}</div><div>}</div><div></div><div></div><div>func (slf *TestService7) AsyncCallTest(){</div><div><span style="white-space:pre">	</span>var input InputData</div><div><span style="white-space:pre">	</span>input.A = 300</div><div><span style="white-space:pre">	</span>input.B = 600</div><div><span style="white-space:pre">	</span>/*slf.AsyncCallNode(1,"TestService6.RPC_Sum",&amp;input,func(output *int,err error){</div><div><span style="white-space:pre">	</span>})*/</div><div><span style="white-space:pre">	</span>//异步调用，在数据返回时，会回调传入函数</div><div><span style="white-space:pre">	</span>//注意函数的第一个参数一定是RPC_Sum函数的第二个参数，err error为RPC_Sum返回值</div><div><span style="white-space:pre">	</span>slf.AsyncCall("TestService6.RPC_Sum",&amp;input,func(output *int,err error){</div><div><span style="white-space:pre">		</span>if err != nil {</div><div><span style="white-space:pre">			</span>fmt.Printf("AsyncCall error :%+v\n",err)</div><div><span style="white-space:pre">		</span>}else{</div><div><span style="white-space:pre">			</span>fmt.Printf("AsyncCall output %d\n",*output)</div><div><span style="white-space:pre">		</span>}</div><div><span style="white-space:pre">	</span>})</div><div>}</div><div></div><div>func (slf *TestService7) GoTest(){</div><div><span style="white-space:pre">	</span>var input InputData</div><div><span style="white-space:pre">	</span>input.A = 300</div><div><span style="white-space:pre">	</span>input.B = 600</div><div></div><div><span style="white-space:pre">	</span>//在某些应用场景下不需要数据返回可以使用Go，它是不阻塞的,只需要填入输入参数</div><div><span style="white-space:pre">	</span>err := slf.Go("TestService6.RPC_Sum",&amp;input)</div><div><span style="white-space:pre">	</span>if err != nil {</div><div><span style="white-space:pre">		</span>fmt.Printf("Go error :%+v\n",err)</div><div><span style="white-space:pre">	</span>}</div><div></div><div><span style="white-space:pre">	</span>//以下是广播方式，如果在同一个子网中有多个同名的服务名，CastGo将会广播给所有的node</div><div><span style="white-space:pre">	</span>//slf.CastGo("TestService6.RPC_Sum",&amp;input)</div><div>}</div><div></div><div>```</div><div>您可以把TestService6配置到其他的Node中，比如NodeId为2中。只要在一个子网，origin引擎可以无差别调用。开发者只需要关注Service关系。同样它也是您服务器架构设计的核心需要思考的部分。</div><div></div><div></div><div>第六章：HttpService使用</div><div>---------------</div><div>HttpService是origin引擎中系统实现的http服务，http接口中常用的GET,POST以及url路由处理。</div><div></div><div>simple_http/TestHttpService.go文件如下：</div><div>```</div><div>package simple_http</div><div></div><div>import (</div><div><span style="white-space:pre">	</span>"fmt"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/service"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/sysservice"</div><div><span style="white-space:pre">	</span>"net/http"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre">	</span>node.Setup(&amp;sysservice.HttpService{})</div><div><span style="white-space:pre">	</span>node.Setup(&amp;TestHttpService{})</div><div>}</div><div></div><div>//新建自定义服务TestService1</div><div>type TestHttpService struct {</div><div><span style="white-space:pre">	</span>service.Service</div><div>}</div><div></div><div>func (slf *TestHttpService) OnInit() error {</div><div><span style="white-space:pre">	</span>//获取系统httpservice服务</div><div><span style="white-space:pre">	</span>httpervice := node.GetService("HttpService").(*sysservice.HttpService)</div><div></div><div><span style="white-space:pre">	</span>//新建并设置路由对象</div><div><span style="white-space:pre">	</span>httpRouter := sysservice.NewHttpHttpRouter()</div><div><span style="white-space:pre">	</span>httpervice.SetHttpRouter(httpRouter,slf.GetEventHandler())</div><div></div><div><span style="white-space:pre">	</span>//GET方法，请求url:http://127.0.0.1:9402/get/query?nickname=boyce</div><div><span style="white-space:pre">	</span>//并header中新增key为uid,value为1000的头,则用postman测试返回结果为：</div><div><span style="white-space:pre">	</span>//head uid:1000, nickname:boyce</div><div><span style="white-space:pre">	</span>httpRouter.GET("/get/query", slf.HttpGet)</div><div></div><div><span style="white-space:pre">	</span>//POST方法 请求url:http://127.0.0.1:9402/post/query</div><div><span style="white-space:pre">	</span>//返回结果为：{"msg":"hello world"}</div><div><span style="white-space:pre">	</span>httpRouter.POST("/post/query", slf.HttpPost)</div><div></div><div><span style="white-space:pre">	</span>//GET方式获取目录下的资源，http://127.0.0.1:port/img/head/a.jpg</div><div><span style="white-space:pre">	</span>httpRouter.SetServeFile(sysservice.METHOD_GET,"/img/head/","d:/img")</div><div></div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div>func (slf *TestHttpService) HttpGet(session *sysservice.HttpSession){</div><div><span style="white-space:pre">	</span>//从头中获取key为uid对应的值</div><div><span style="white-space:pre">	</span>uid := session.GetHeader("uid")</div><div><span style="white-space:pre">	</span>//从url参数中获取key为nickname对应的值</div><div><span style="white-space:pre">	</span>nickname,_ := session.Query("nickname")</div><div><span style="white-space:pre">	</span>//向body部分写入数据</div><div><span style="white-space:pre">	</span>session.Write([]byte(fmt.Sprintf("head uid:%s, nickname:%s",uid,nickname)))</div><div><span style="white-space:pre">	</span>//写入http状态</div><div><span style="white-space:pre">	</span>session.WriteStatusCode(http.StatusOK)</div><div><span style="white-space:pre">	</span>//完成返回</div><div><span style="white-space:pre">	</span>session.Done()</div><div>}</div><div></div><div>type HttpRespone struct {</div><div><span style="white-space:pre">	</span>Msg string `json:"msg"`</div><div>}</div><div></div><div>func (slf *TestHttpService) HttpPost(session *sysservice.HttpSession){</div><div><span style="white-space:pre">	</span>//也可以采用直接返回数据对象方式，如下：</div><div><span style="white-space:pre">	</span>session.WriteJsonDone(http.StatusOK,&amp;HttpRespone{Msg: "hello world"})</div><div>}</div><div></div><div>```</div><div>注意，要在main.go中加入import _ "orginserver/simple_service"，并且在config/cluster/subnet/cluster.json中的ServiceList加入服务。</div><div></div><div></div><div></div><div>第七章：TcpService服务使用</div><div>---------------</div><div>TcpService是origin引擎中系统实现的Tcp服务，可以支持自定义消息格式处理器。只要重新实现network.Processor接口。目前内置已经实现最常用的protobuf处理器。</div><div></div><div>simple_tcp/TestTcpService.go文件如下：</div><div>```</div><div>package simple_tcp</div><div></div><div>import (</div><div><span style="white-space:pre">	</span>"fmt"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/network/processor"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/service"</div><div><span style="white-space:pre">	</span>"github.com/duanhf2012/origin/sysservice"</div><div><span style="white-space:pre">	</span>"github.com/golang/protobuf/proto"</div><div><span style="white-space:pre">	</span>"orginserver/simple_tcp/msgpb"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre">	</span>node.Setup(&amp;sysservice.TcpService{})</div><div><span style="white-space:pre">	</span>node.Setup(&amp;TestTcpService{})</div><div>}</div><div></div><div>//新建自定义服务TestService1</div><div>type TestTcpService struct {</div><div><span style="white-space:pre">	</span>service.Service</div><div><span style="white-space:pre">	</span>processor *processor.PBProcessor</div><div><span style="white-space:pre">	</span>tcpService *sysservice.TcpService</div><div>}</div><div></div><div>func (slf *TestTcpService) OnInit() error {</div><div><span style="white-space:pre">	</span>//获取安装好了的TcpService对象</div><div><span style="white-space:pre">	</span>slf.tcpService =&nbsp; node.GetService("TcpService").(*sysservice.TcpService)</div><div></div><div><span style="white-space:pre">	</span>//新建内置的protobuf处理器，您也可以自定义路由器，比如json，后续会补充</div><div><span style="white-space:pre">	</span>slf.processor = processor.NewPBProcessor()</div><div></div><div><span style="white-space:pre">	</span>//注册监听客户连接断开事件</div><div><span style="white-space:pre">	</span>slf.processor.RegisterDisConnected(slf.OnDisconnected)</div><div><span style="white-space:pre">	</span>//注册监听客户连接事件</div><div><span style="white-space:pre">	</span>slf.processor.RegisterConnected(slf.OnConnected)</div><div><span style="white-space:pre">	</span>//注册监听消息类型MsgType_MsgReq，并注册回调</div><div><span style="white-space:pre">	</span>slf.processor.Register(uint16(msgpb.MsgType_MsgReq),&amp;msgpb.Req{},slf.OnRequest)</div><div><span style="white-space:pre">	</span>//将protobuf消息处理器设置到TcpService服务中</div><div><span style="white-space:pre">	</span>slf.tcpService.SetProcessor(slf.processor,slf.GetEventHandler())</div><div></div><div><span style="white-space:pre">	</span>return nil</div><div>}</div><div></div><div></div><div>func (slf *TestTcpService) OnConnected(clientid uint64){</div><div><span style="white-space:pre">	</span>fmt.Printf("client id %d connected\n",clientid)</div><div>}</div><div></div><div></div><div>func (slf *TestTcpService) OnDisconnected(clientid uint64){</div><div><span style="white-space:pre">	</span>fmt.Printf("client id %d disconnected\n",clientid)</div><div>}</div><div></div><div>func (slf *TestTcpService) OnRequest (clientid uint64,msg proto.Message){</div><div><span style="white-space:pre">	</span>//解析客户端发过来的数据</div><div><span style="white-space:pre">	</span>pReq := msg.(*msgpb.Req)</div><div><span style="white-space:pre">	</span>//发送数据给客户端</div><div><span style="white-space:pre">	</span>err := slf.tcpService.SendMsg(clientid,&amp;msgpb.Req{</div><div><span style="white-space:pre">		</span>Msg: proto.String(pReq.GetMsg()),</div><div><span style="white-space:pre">	</span>})</div><div><span style="white-space:pre">	</span>if err != nil {</div><div><span style="white-space:pre">		</span>fmt.Printf("send msg is fail %+v!",err)</div><div><span style="white-space:pre">	</span>}</div><div>}</div><div>```</div><div></div><div></div><div>第八章：其他系统模块介绍</div><div>---------------</div><div>* sysservice/wsservice.go:支持了WebSocket协议，使用方法与TcpService类似</div><div>* sysmodule/DBModule.go:对mysql数据库操作</div><div>* sysmodule/RedisModule.go:对Redis数据进行操作</div><div>* sysmodule/HttpClientPoolModule.go:Http客户端请求封装</div><div>* log/log.go:日志的封装，可以使用它构建对象记录业务文件日志</div><div>* util:在该目录下，有常用的uuid,hash,md5,协程封装等工具库</div><div>* https://github.com/duanhf2012/originservice: 其他扩展支持的服务可以在该工程上看到，目前支持firebase推送的封装。</div><div></div><div></div><div>**欢迎加入origin服务器开发QQ交流群:168306674，有任何疑问我都会及时解答**</div><div></div><div>提交bug及特性: https://github.com/duanhf2012/origin/issues</div><div></div><div></div><div></div><img src ="http://www.cppblog.com/API/aggbug/217287.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2020-05-07 16:06 <a href="http://www.cppblog.com/API/archive/2020/05/07/217287.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>golang游戏服务器引擎</title><link>http://www.cppblog.com/API/archive/2020/05/07/217286.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Thu, 07 May 2020 08:04:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2020/05/07/217286.html</guid><wfw:comment>http://www.cppblog.com/API/comments/217286.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2020/05/07/217286.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/217286.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/217286.html</trackback:ping><description><![CDATA[<span data-offset-key="51d80-0-0" style="color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, &quot;Source Han Sans SC&quot;, &quot;Noto Sans CJK SC&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-size: 15px; white-space: pre-wrap; background-color: #ffffff;"><span data-text="true">现在go语言比较流行的有leaf,gowold,origin。前两个比较基础，实现集群还需要进行二次的编码设计。origin不一样，只需要通过配置方便快速的集群。</span></span>origin总体设计如go语言设计一样，总是尽可能的提供简洁和易用的模式，快速开发。 能够根据业务需求快速并灵活的制定服务器架构。 利用多核优势，将不同的service配置到不同的node，并能高效的协同工作。 将整个引擎抽象三大对象，node,service,module。通过统一的组合模型管理游戏中各功能模块的关系。&nbsp;<br /><br /><br /><div>origin引擎三大对象关系</div><div>---------------</div><div>* Node:&nbsp; &nbsp;可以认为每一个Node代表着一个origin进程</div><div>* Service:一个独立的服务可以认为是一个大的功能模块，他是Node的子集，创建完成并安装Node对象中。服务可以支持对外部RPC等功能。</div><div>* Module: 这是origin最小对象单元，强烈建议所有的业务模块都划分成各个小的Module组合，origin引擎将监控所有服务与Module运行状态，例如可以监控它们的慢处理和死循环函数。Module可以建立树状关系。Service本身也是Module的类型。<br /><br />更加详细的参照项目地址：<a href="https://github.com/duanhf2012/origin">https://github.com/duanhf2012/origin</a></div><img src ="http://www.cppblog.com/API/aggbug/217286.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2020-05-07 16:04 <a href="http://www.cppblog.com/API/archive/2020/05/07/217286.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SVN分支/合并原理及最佳实践(转)</title><link>http://www.cppblog.com/API/archive/2017/04/12/214834.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Wed, 12 Apr 2017 07:15:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2017/04/12/214834.html</guid><wfw:comment>http://www.cppblog.com/API/comments/214834.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2017/04/12/214834.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/214834.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/214834.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; background-color: #ffffff;">使用svn几年了，一直对分支和合并敬而远之，一来是因为分支的管理不该我操心，二来即使涉及到分支的管理，也不敢贸然使用合并功能，生怕合并出了问题对团队造成不良影响，最主要的原因是，自己对分支的目的和合并的方法不甚了解，这才是硬伤。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">最近由于适配机型的需要（本人从事手机客户端的开发），需要经常接触分支和合并两项工作，突然发现这玩意整不明白很难开展工作，遂这两天着重研究了一下，有点收获，怕以后忘了，故趁着余温尚在赶紧写下来，好记性不如烂笔头嘛。下文的实践主要是参考了TortoiseSVN的帮助文档和Subversion的在线文档，Subversion的在线文档：<a target="_blank" href="http://svnbook.red-bean.com/en/1.5/svn-book.html" style="color: #336699; text-decoration: none;">http://svnbook.red-bean.com/en/1.5/svn-book.html</a></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="color: #336699;"><br /></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">话说我公司现在的源代码管理挺乱的，svn目录并没有采取标准的source/branches、source/trunk结构，主线和分支放得到处都是，release版本也并没有当成tag处理，而是当成branch来管理，经常还要在release版本上改来改去。。。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">先说说什么是branch。按照Subversion的说法，一个branch是某个development line（通常是主线也即trunk）的一个拷贝，见下图：<br /><img src="http://www.cppblog.com/images/cppblog_com/api/1.gif" width="321" height="135" alt="" /><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">branch存在的意义在于，在不干扰trunk的情况下，和trunk并行开发，待开发结束后合并回trunk中，在branch和trunk各自开发的过程中，他们都可以不断地提交自己的修改，从而使得每次修改在repository中都有记录。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">设想以下场景，如果你的项目需要开发一个新功能，而该功能可能会修改项目中的绝大多数文件，而与此同时，你的另一位同事正在进行bug fix，如果你的新功能不在branch中开发而直接在trunk中开发，那么你极有可能影响另一位同事的bug fix，他/她在bug修复中可能会遇到各种各样的问题，因为你的频繁提交代码引入了过多的不稳定因素。你可能会说，那我在开发的过程中不提交不就行了，等到我全部开发结束我再提交，是，你可以这么做，那还要<a href="http://lib.csdn.net/base/git" title="Git知识库" target="_blank" style="color: #df3434; text-decoration: none; font-weight: bold;">版本控制</a>干什么呢？也许等到你最后提交代码的时候（也许一周，也许两周？），你会发现有一大堆conflict等着你resolve。。。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">那么，正确的做法是什么？使用branch，从trunk创建branch，然后在你的branch上开发，开发完成后再合并到trunk中。<br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">关于branch先讲到这里，下面说说什么叫做合并。很好理解，当branch开发完成后（包括必要的<a href="http://lib.csdn.net/base/softwaretest" title="软件测试知识库" target="_blank" style="color: #df3434; text-decoration: none; font-weight: bold;">测试</a>），将branch中的修改同步到trunk中，这个过程有可能包括修改文件、增加文件、删除文件等等。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">说到这里，貌似本文差不多可以结束了，不就是分支和合并么？只要再简单地说说如何建立分支和如何合并就可以收尾了，可能只需两个命令，也可能只需鼠标点几下然后键盘敲两下即可。其实事情远非这么简单，爱动脑筋的同学可能会问了，将branch的改动merge到trunk的时候，和上文说的直接在trunk中全部开发完然后提交有何区别？你最后还不是要处理一大堆conflict？</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">这个问题问得非常好，其实这正是本文的重点：branch和trunk在并行开发的过程中如何感知对方，branch如何才能在开发过程中不会和trunk越走越远，导致最后无法合并？试想一下，如果在你开发branch的过程中，trunk中的某个类文件已经被删除了（这可能是另外一个家伙在另一个branch上开发了两周后才合并到trunk的），而你竟然在这个类文件上做了大量修改，试问你到最后合并回trunk的时候该有多蛋疼？解决这一问题的唯一手段是，branch要不停地和trunk保持同步，你要及时地知道trunk都做了什么修改，这些修改是否会影响你正在开发的新功能，如果需要，你必须及时调整branch的代码，使之能与trunk&#8220;兼容&#8221;。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">那么如何让branch和trunk保持同步？合并，从trunk合并到branch，你没听错，是从trunk合并到branch。关于TortoiseSVN的合并，有几点需要注意：</p><ul style="color: #333333; font-family: Arial; background-color: #ffffff;"><li>TortoiseSVN的合并发生在本地，也即你的working copy中，你无需过多担心会对repository中的代码造成影响<br /></li></ul><ul style="color: #333333; font-family: Arial; background-color: #ffffff;"><li>不管是从trunk合并到branch还是最终从branch合并回trunk，在每次合并前最好先update，然后将本地的修改先全部commit，保护好现场，万一合并不理想随时都可以revert</li><li>合并完成后看是否能正确编译，然后测试验证，最后将合并后的改动提交到repository</li></ul><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">下面我将step by step地演示如何一次完整的branching和merging，包括创建分支、分支开发、分支和主线同步，分支合并到主线的全过程，甚至包括如何在本地创建一个测试用的repository。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">首先需要安装TortoiseSVN，我安装的版本是：TortoiseSVN 1.6.15, Build 21041 - 32 Bit , 2011/03/23 18:00:27</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>1、本地Repository的创建</strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">repository的创建很简单，假设我要在D:\TortoiseSVN\TestRepository目录中创建repository，只需右键TestRepository目录，依次选择"TortoiseSVN" -&gt; "Create repository here"便完成了repository的创建。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>2、Check out</strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">假设要check out到D:\TortoiseSVN\TestSVN，同样很简单，在D:\TortoiseSVN目录下创建TestSVN目录，然后在该目录上右键，选择"SVN Check out..."，在弹出的窗口中的"URL of repository"中填入"file:///D:/TortoiseSVN/TestRepository"，其他默认即可，最后点击ok。<br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>3、trunk创建新项目MyProject</strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">相当简单就不赘述了，只列出本次操作所作出的修改：<br /><img src="http://www.cppblog.com/images/cppblog_com/api/2.gif" width="414" height="350" alt="" /><br /><br /><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>4、创建branch</strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">在/trunk/MyProject目录上右键，依次选择"TortoiseSVN" -&gt; "Branch/tag..."，在弹出窗口的"To URL"中填入分支的地址，在这里目标revision选择HEAD revision，如下图所示，添加log后点击ok分支便建立了。这个操作速度非常快，新建的branch在repository中其实只是一个指向trunk某个revision的软连接而已，并没有真的复制文件。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><img src="http://www.cppblog.com/images/cppblog_com/api/3.gif" width="468" height="511" alt="" /><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>5、Check out分支</strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">右键TestSVN目录选择"TortoiseSVN Update"即可将刚刚建立的分支下载回本地。进入/branches/MyProject目录下你会发现其文件结构和/trunk/MyProject一模一样。<br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>6、branch提交一个新文件</strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><img src="http://www.cppblog.com/images/cppblog_com/api/4.gif" width="426" height="164" alt="" /><br /><strong style="font-size: 16px;">7、trunk紧接着提交一个修改<br /></strong><img src="http://www.cppblog.com/images/cppblog_com/api/8.gif" width="420" height="167" alt="" /><br /><br /><strong style="font-size: 16px;">8、branch再次提交一个修改<br /></strong><img src="http://www.cppblog.com/images/cppblog_com/api/9.gif" width="440" height="165" alt="" /><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>9、将trunk中的修改同步到branch</strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">6-8演示的是branch和trunk在独立、并行地开发。为了防止在&#8220;错误&#8221;的道路上越走越远，现在branch意识到是时候和trunk来一次同步了（将trunk合并到branch）。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">首先，在本地trunk中先update一下，有冲突的解决冲突，保证trunk和repository已经完全同步，然后在/branches/MyProject上右键，依次选择"TortoiseSVN" -&gt; &#8220;Merge...&#8221;，在弹出的窗口中选择第一项"Merge a range of revision"，这个类型的Merge已经介绍得很清楚，适用于将某个分支或主线上提交的多个revision间的变化合并到另外一个分支上。<br /><br /><img src="http://www.cppblog.com/images/cppblog_com/api/10.gif" width="520" height="447" alt="" /><br /><br />点击next后，出现如下窗口：<br /><img src="http://www.cppblog.com/images/cppblog_com/api/11.gif" width="520" height="447" alt="" /><br />由于是要从trunk合并到branch，理所当然这里的"URL to merge from"应该填trunk的路径，"Revision range to merge"很好理解，就是你要将trunk的哪些revision所对应的变化合并到branch中，可以是某一连串的revision，比如4-7，15-HEAD，也可以是某个单独的revision号。由于在r4中，trunk修改了Person.<a href="http://lib.csdn.net/base/javase" title="Java SE知识库" target="_blank" style="color: #df3434; text-decoration: none; font-weight: bold;">Java</a>中的talk()方法，所以这里的revision只需填4即可。点击next后出现下图：<br /><img src="http://www.cppblog.com/images/cppblog_com/api/12.gif" width="520" height="447" alt="" /><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">在这里只需保留默认设置即可。在点击Merge按钮前你可以先Test merge一把，看成功与否，以及merge的详细信息。点击Merge按钮后trunk所做的修改将同步到branch中。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>10、提交合并后的branch<br /><img src="http://www.cppblog.com/images/cppblog_com/api/13.gif" width="434" height="185" alt="" /><br /><br /></strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">至此，branch已经完全和trunk同步，branch和trunk的代码相处很融洽，没有任何冲突，如果branch已经开发结束，那是时候将branch合并回trunk了，当然，如果branch还要继续开发，那你将不断地重复6-10这几个步骤。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>11、将branch合并回trunk</strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">在/trunk/MyProject上右键（注意是在主线的目录上右键），依次选择"TortoiseSVN" -&gt; "Merge..."，在弹出的窗口中，Merge type选择第二项"Reintegrate a branch"，这种类型的合并适合在分支开发结束后将所有的改动合并回主线。</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong><img src="http://www.cppblog.com/images/cppblog_com/api/14.gif" width="520" height="447" alt="" /><br /><br /></strong></span>点击next后出现如下窗口：<br /><span style="font-size: 16px;"><strong><img src="http://www.cppblog.com/images/cppblog_com/api/15.gif" width="520" height="447" alt="" /><br /></strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">在这里，"From URL"选择/branches/MyProject，无需选择revision号，Reintegrate会将branch上所有修改合并到trunk。后面的步骤和上文第9步中的一样，不再啰嗦了。如无意外，branch将成功合并到trunk，你需要做的只是将合并后的trunk赶紧commit！</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>12、提交合并后的trunk</strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">so easy...</p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><span style="font-size: 16px;"><strong>13、删除branch</strong></span></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">如果你认为你新加的功能已经开发完成了，你可以删除你的分支<br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">到这里，我已经给你演示完了整个过程，我一身的汗也下来了，我想罢工了，不过最后我们还是看看所有的log信息吧，通过log能发现我们干的所有事情：<br /><img src="http://www.cppblog.com/images/cppblog_com/api/16.gif" width="577" height="230" alt="" /><br />r1-r7正是我上文在干的事情，从Message中你能发现我对trunk和branch都干了什么，另外，在Log Messages窗口的左下角勾选了"Include merged revisions"你还能看到额外的Merge information：<br /><img src="http://www.cppblog.com/images/cppblog_com/api/17.gif" width="575" height="330" alt="" /><br /><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">图中灰色的是和merge相关的log，共发生了两次merge，第一次是在r6，在r6中，branch合并了trunk在r4时提交的变化；第二次是在r7，在r7中，trunk合并了branch从r2到r6的所有变化。<br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;"><br /></p><p style="color: #333333; font-family: Arial; background-color: #ffffff;">终于可以写写总结了：</p><ul style="color: #333333; font-family: Arial; background-color: #ffffff;"><li>branch主要用于新功能的开发</li><li>合并发生在本地working copy，只要你不提交就不会影响到repository</li><li>合并前一定要先update、commit，保证不会out of day，并将本地的修改保存到repository</li><li>branch和trunk并行开发的过程中，要经常同步，将trunk的修改合并到branch，合并时选择"Merge a range of revision"</li><li>branch最后合并回trunk时，merge type选择"Reintegrate a branch"</li></ul><img src ="http://www.cppblog.com/API/aggbug/214834.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2017-04-12 15:15 <a href="http://www.cppblog.com/API/archive/2017/04/12/214834.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>protobuf repeated类型的使用</title><link>http://www.cppblog.com/API/archive/2014/12/09/209070.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Tue, 09 Dec 2014 11:14:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2014/12/09/209070.html</guid><wfw:comment>http://www.cppblog.com/API/comments/209070.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2014/12/09/209070.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/209070.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/209070.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">protobuf是Google开发的一个序列化框架，类似XML，JSON，基于二进制，比传统的XML表示同样一段内容要短小得多。通过protobuf，可以很轻松的调用相关方法来完成业务数据的序列化与反序列化。protobuf repeated类型相当于std的vector，可以用来存放N个相同类型的内容，文章将简单介绍protobuf repeated的使用。</p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">首先定义一个protobuf结构，如下：<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->message&nbsp;Person&nbsp;{<br />&nbsp;&nbsp;required&nbsp;int32&nbsp;age&nbsp;=&nbsp;1;<br />&nbsp;&nbsp;required&nbsp;<span style="color: #0000FF; ">string</span>&nbsp;name&nbsp;=&nbsp;2;<br />}<br /><br />message&nbsp;Family&nbsp;{<br />&nbsp;&nbsp;repeated&nbsp;Person&nbsp;person&nbsp;=&nbsp;1;<br />}</div><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><br />下面我们以例子简单说明如何使用：<br /></p><div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">int</span>&nbsp;main(<span style="color: #0000FF; ">int</span>&nbsp;argc,&nbsp;<span style="color: #0000FF; ">char</span>*&nbsp;argv[])<br />{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;GOOGLE_PROTOBUF_VERIFY_VERSION;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;Family&nbsp;family;<br />&nbsp;&nbsp;&nbsp;&nbsp;Person*&nbsp;person;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;添加一个家庭成员，John</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;person&nbsp;=&nbsp;family.add_person();<br />&nbsp;&nbsp;&nbsp;&nbsp;person-&gt;set_age(25);<br />&nbsp;&nbsp;&nbsp;&nbsp;person-&gt;set_name("John");<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;添加一个家庭成员，Lucy</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;person&nbsp;=&nbsp;family.add_person();<br />&nbsp;&nbsp;&nbsp;&nbsp;person-&gt;set_age(23);<br />&nbsp;&nbsp;&nbsp;&nbsp;person-&gt;set_name("Lucy");<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;添加一个家庭成员，Tony</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;person&nbsp;=&nbsp;family.add_person();<br />&nbsp;&nbsp;&nbsp;&nbsp;person-&gt;set_age(2);<br />&nbsp;&nbsp;&nbsp;&nbsp;person-&gt;set_name("Tony");<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;显示所有家庭成员</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;size&nbsp;=&nbsp;family.person_size();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;"这个家庭有&nbsp;"&nbsp;&lt;&lt;&nbsp;size&nbsp;&lt;&lt;&nbsp;"&nbsp;个成员，如下："&nbsp;&lt;&lt;&nbsp;endl;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(<span style="color: #0000FF; ">int</span>&nbsp;i=0;&nbsp;i&lt;size;&nbsp;i++)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Person&nbsp;psn&nbsp;=&nbsp;family.person(i);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;i+1&nbsp;&lt;&lt;&nbsp;".&nbsp;"&nbsp;&lt;&lt;&nbsp;psn.name()&nbsp;&lt;&lt;&nbsp;",&nbsp;年龄&nbsp;"&nbsp;&lt;&lt;&nbsp;psn.age()&nbsp;&lt;&lt;&nbsp;endl;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;getchar();<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />}</div><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><br /></p><img src ="http://www.cppblog.com/API/aggbug/209070.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2014-12-09 19:14 <a href="http://www.cppblog.com/API/archive/2014/12/09/209070.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>cocos2dx环境搭建</title><link>http://www.cppblog.com/API/archive/2014/07/01/207481.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Tue, 01 Jul 2014 09:34:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2014/07/01/207481.html</guid><wfw:comment>http://www.cppblog.com/API/comments/207481.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2014/07/01/207481.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/207481.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/207481.html</trackback:ping><description><![CDATA[<div>一． &nbsp; &nbsp; &nbsp; 前期准备</div><div></div><div>cocos2d-x2.2.1 &nbsp;</div><div>2013年11月19日更新</div><div></div><div>下载地址：http://www.cocos2d-x.org/download</div><div></div><div>&nbsp;</div><div></div><div>2.jdk</div><div></div><div>java环境是必须的，这个在官网上下载</div><div></div><div>下载地址：http://www.java.com/zh_CN/download/manual.jsp</div><div></div><div>3. Android开发环境</div><div></div><div>这个是android交叉编译必须的IDE环境，内含Eclipse</div><div></div><div>下载地址：http://developer.android.com/sdk/index.html</div><div></div><div>&nbsp;</div><div></div><div>4.Android NDK</div><div></div><div>android交叉编译时，对C/C++代码的解释编译工具</div><div></div><div>下载地址：http://developer.android.com/tools/sdk/ndk/index.html</div><div></div><div>&nbsp;</div><div></div><div>5.python</div><div></div><div>cocos2d-x2.0版本以后用python脚本来创建工程，所以需要python环境</div><div></div><div>下载地址：http://www.python.org/download/</div><div></div><div>注意：请下载python2.7.6 &nbsp;64位版本，不要下3.3的版本</div><div></div><div>&nbsp;</div><div></div><div>&nbsp;</div><div></div><div>6.cygwin</div><div></div><div>对cocos2d-x本地C/C++代码的解释编译工具</div><div></div><div>下载地址：http://cygwin.com/install.html</div><div></div><div>&nbsp;</div><div></div><div>至此我们所需要的软件都已经准备完毕，接下来可以开始正式搭建环境了!</div><div></div><div>二． &nbsp; &nbsp; &nbsp; 搭建Android开发环境</div><div></div><div>1.java环境</div><div></div><div>android环境的搭建少不了java，先把下载好的JDK选择默认路径安装好后，然后用wmic命令向系统添加java的环境变量。</div><div></div><div>win+R运行cmd，输入以下三个命令：</div><div></div><div>wmic ENVIRONMENT create name="JAVA_HOME",username="&lt;system&gt;",VariableValue="C:\Program Files\Java\jre7"</div><div></div><div>以上为一行</div><div>wmic ENVIRONMENT create name="CLASSPATH",username="&lt;system&gt;",VariableValue=";%JAVA_HOME%\lib\;"</div><div></div><div>以上为一行</div><div>wmic ENVIRONMENT where "name='path' and username='&lt;system&gt;'" set VariableValue="%path%;C:\Program Files\Java\jre7\bin"</div><div></div><div>以上为一行</div><div></div><div>然后进入系统环境变量设置界面更新一下，重启cmd，试一下输入java，只要不是出现&#8220;java不是内部命令或外部命令&#8221;之类的，就表示你设置成功了。</div><div></div><div>2.Android环境</div><div></div><div>找到我们下载的adt-bundle-windows-x86_64-20131030.zip，解压，路径可以自己配置，还是注意英文路径，不加空格即可。</div><div></div><div>接着运行adt-bundle-windows-x86_64-20131030\eclipse下的eclipse（ADT自带Eclipse编译环境），选择工程文件夹，这里可以随意配置</div><div></div><div>&nbsp;</div><div></div><div>接着关掉说明页，进入主界面。在主界面点击配置SDK</div><div></div><div>然后可以按照需求选择Android SDK的版本，这里我选择下载Android（API 8），然后选择安装</div><div></div><div>&nbsp;</div><div></div><div>&nbsp;</div><div></div><div>&nbsp;</div><div></div><div>慢慢等待下载安装结束。</div><div></div><div>接下来配置Android VDM</div><div></div><div>&nbsp;</div><div></div><div>然后选择DeviceDefinitions，随便选择一个创建，好像是现在的VDM不支持OpenGL的高版本，所以我使会用BlueStacks模拟器来调试，这里只是生成apk</div><div></div><div>&nbsp;</div><div></div><div>三． &nbsp; &nbsp; &nbsp; 安装cygwin，配置Android NDK</div><div></div><div>运行下载好的cygwin-setup-x86_64.exe，看到下列安装界面</div><div></div><div>&nbsp;</div><div></div><div>点击下一步</div><div></div><div>&nbsp;</div><div></div><div>继续</div><div></div><div>&nbsp;</div><div></div><div>&nbsp;默认路径安装，然后选择下载保存的路径，这个大家可以自己配置，安装完毕后最好做个备份，免得再次需要安装时还要下载</div><div></div><div>&nbsp;</div><div></div><div>默认选择，下一步</div><div>选择第一个网站</div><div>这里注意了，一定要将红框标出来的点击一下，变成install</div><div></div><div>&nbsp;</div><div></div><div>点击下一步，漫长的等待下载~~~~~~</div><div></div><div>终于安装完毕，我们赶紧打开来试试吧</div><div></div><div>第一次点开cygwin目录会在c:\cygwin64\home文件下生成以系统登录账户为名字的文件夹</div><div></div><div>现在，将我们下载下来的Android NDK也就是android-ndk-r9b-windows-x86_64.zip解压缩至英文路径下，这个路径将会在接下来写入到cygwin的.bash_profile配置文件中，好了，我的解压路径为：D:\ android-ndk-r9b</div><div>注意：该路径不能存在空格，全英文</div><div></div><div>大家在c:\cygwin\home文件下生成的以系统登录账户为名字的文件夹下找到.bash_profile文件，点击右键，用EditPlus软件打开，在结尾处输入回车，接着输入下列语句：</div><div></div><div>NDK_ROOT="/cygdrive/d/android-ndk-r9d"</div><div></div><div>export NDK_ROOT</div><div></div><div>&nbsp;</div><div></div><div>NDK_MODULE_PATH="/cygdrive/d/cocos2d-x-2.2.1:/cygdrive/d/cocos2d-x-2.2.1/cocos2dx/platform/third_party/android/prebuilt"</div><div></div><div>export NDK_MODULE_PATH</div><div></div><div>&nbsp;</div><div></div><div>然后点击保存，关闭。这里的cygwin是指本地磁盘，d是d盘，后面是NDK路径，大家按照自己的文件路径填写，注意windows路径中&#8220;\&#8221;和cygwin中&#8220;/&#8221;的区别。顺便提一句，目录一直要写到有ndk-build.cmd文件的文件夹。</div><div></div><div>四． &nbsp; &nbsp; &nbsp; 安装python，创建自己的cocos2d-x工程</div><div></div><div>安装我们已经下载好的python-2.7.6.amd64，选择默认路径。</div><div></div><div>&nbsp;</div><div></div><div>安装完毕，我们接下来使用python命令创建自己的cocos2d-x工程。</div><div></div><div>首先需要设置python的系统环境，由于刚才是默认安装，所以python的安装路径为C:\Python27\，大家可以手动在开始-&gt;计算机（在上面点右键）-&gt;属性-&gt;高级系统设置-&gt;环境变量中设置path路径，添加python的安装目录。</div><div></div><div>好了，赶紧试一下我们的配置是否正确吧。在cmd输入命令：</div><div></div><div>python -?</div><div></div><div>然后balabala...出现一堆，这就说明我们的python配置好了。</div><div></div><div>接下来使用python创建工程。进入cocos2d-x-2.2.1目录下的tools-&gt;project-creator，大家可以看到有一个create_project.py脚本，如果有兴趣可以右键在IDE中打开来看看，从中可以截取到该脚本的使用方法</div><div></div><div>&nbsp;</div><div></div><div>好了，我们赶快将这个脚本使用起来吧</div><div></div><div>先在cocos2d-x-2.2.1目录下建一个projects文件夹，在project-creator目录下按住shift+鼠标右键，选择在此处打开命令窗口，输入命令：</div><div></div><div>python create_project.py -project HelloWorld -package org.HelloWorld.game -language cpp</div><div></div><div>然后等待结果</div><div></div><div>&nbsp;</div><div></div><div>大家可以看到，我们的工程创建完毕了，其中，HelloWorld是我们命令中输入的工程名，也就是在cocos2d-x-2.2.1-&gt;projects文件夹下创建了我们的工程，名字就是HelloWorld，在HelloWorld文件夹下的proj.android文件夹就是我们之后需要编译的android项目，创建命令后面的org.HelloWorld.game是安卓APK的识别名，大家可以按照&#8220;xxx.xxx.xxx&#8221;的格式自己命名。</div><div></div><div>这里我写了一个bat批处理，大家可以放在project-creator目录下，以后可以很方便的创建工程。</div><div></div><div>在project-creator目录下点右键创建一个文本文档，打开，将以下内容复制进去，然后点保存，更改文件的后缀名为bat即可</div><div></div><div>-----------------------------------------------------------------------------------------</div><div></div><div>@echo off</div><div>:label1</div><div>@cls</div><div>echo 欢迎使用Python创建Cocos2d-x工程</div><div>set /p project=请输入需要创建的工程名:</div><div>set /p aID=请输入需要创建的android版本包标识名:</div><div>echo 您输入的工程名为%project%</div><div>echo 您输入的android版本包标识名为%aID%</div><div>echo 确认创建工程吗?</div><div>CHOICE /C 123 /M "确认请按 1，取消请按 2，或者退出请按 3。"</div><div>echo %errorlevel%</div><div>if %errorlevel%==1 goto label2</div><div>if %errorlevel%==2 goto label1</div><div>if %errorlevel%==3 goto label3</div><div>:label2</div><div>echo 正在创建工程...</div><div>python create_project.py -project %project% -package %aID% -language cpp</div><div>:label3</div><div>pause</div><div></div><div>-----------------------------------------------------------------------------------------</div><div></div><div>五． &nbsp; &nbsp; &nbsp; 在Ecliopse下编译Android项目</div><div></div><div>好了，以上我们所有的环境都已搭建完成，在将我们的项目导入eclipse之前，我们还需要将cocos2d-x-2.2.1\cocos2dx\platform\android\java\src下的org文件夹拷贝至我们的项目中，也就是cocos2d-x-2.2.1\projects\HelloWorld\proj.android\src下，由于我们之前创建项目时定的android包名前面也是org，所以会有覆盖选项，请选择合并覆盖即可</div><div></div><div>接着，回到eclipse环境，导入项目</div><div></div><div>&nbsp;</div><div></div><div>&nbsp;</div><div></div><div>&nbsp;</div><div></div><div>注意在选择路径时写到HelloWorld文件夹下即可</div><div></div><div>导入工程后，在工程HelloWorld上点选右键，选择Properties</div><div></div><div>&nbsp;</div><div></div><div>&nbsp;</div><div></div><div>选择builders，点击New</div><div></div><div>&nbsp;</div><div></div><div>选择program</div><div></div><div>&nbsp;</div><div></div><div>然后在接下来的界面中的</div><div></div><div>name栏输入：Native_Builder</div><div></div><div>Location栏输入：C:\cygwin\bin\bash.exe</div><div></div><div>Arguments栏输入：--login -c "cd &nbsp;D:/cocos2d-x-2.2.1/projects/HelloWorld/proj.android &amp;&amp; /cygdrive/d/android-ndk-r9b/ndk-build"</div><div></div><div>&nbsp;</div><div></div><div>以上为一行</div><div></div><div>&nbsp;</div><div></div><div>选择OK，选中Native_Builder，并将其调到最上面</div><div></div><div>&nbsp;</div><div></div><div>然后选择C/C++ Build-&gt;Environment-&gt;Add</div><div></div><div>&nbsp;</div><div></div><div>&nbsp;</div><div></div><div>接下来在Name栏输入path，在Value栏输入C:\cygwin\bin</div><div></div><div>&nbsp;</div><div></div><div>然后在Java Build Path里面选择Libraries栏，将Android Dependencies以及Android Private Libraries两个library删掉</div><div></div><div>&nbsp;</div><div></div><div>（说明一下，以上我们是将cygwin的编译环境合并到了Eclipse里，Eclipse利用cygwin并调用cygwin的bash以及make，通过NDK来编译我们的Android程序，所以每次导入新的工程都要将上述步骤重新配置一下，这点非常重要，如果配置不正确，会导致很多莫名其妙的报错，最典型的错误就是提示找不到bash命令什么的~~~~）</div><div></div><div>好了，现在我们可以生成APK文件了，在主界面选中自己的工程，然后在命令条上选择Run-&gt;Run as-&gt;Android Application</div><div></div><div>&nbsp;</div><div></div><div>&nbsp;</div><div></div><div>在编译的过程中，会有各种编译错误的问题，这是我碰到的三个：</div><div></div><div>please define NDK_ROOT</div><div>解决方法：</div><div></div><div>在工程的proj.android目录下的build_native.sh中加入</div><div></div><div>export NDK_ROOT=/cygdrive/e/android-ndk-r9</div><div></div><div>Android NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml &nbsp;&nbsp;</div><div>解决办法：</div><div>在该工程的jni文件夹下，创建（若不存在，才创建）一个名为Application.mk的文件，在其内写一句：</div><div></div><div>APP_PLATFORM := android-8</div><div></div><div>编译成功，但是bin目录下没有生成apk文件</div><div>解决办法：</div><div></div><div>在工程的proj.android目录下的build_native.sh中加入</div><div></div><div>chmod 666 -R "$APP_ANDROID_ROOT"/assets</div><div></div><div>&nbsp;</div><div></div><div>如果以上步骤都按照步骤设定的话，就能够生成APK了，APK存放在proj.android-&gt;bin文件夹下</div><div></div><div>快将APK装在自己的真机上进行测试吧！！！！！</div><div></div><div>以上编译环境就配置结束了。</div><div></div><div>&nbsp;</div><img src ="http://www.cppblog.com/API/aggbug/207481.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2014-07-01 17:34 <a href="http://www.cppblog.com/API/archive/2014/07/01/207481.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>lua常用函数</title><link>http://www.cppblog.com/API/archive/2014/06/27/207436.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Fri, 27 Jun 2014 07:34:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2014/06/27/207436.html</guid><wfw:comment>http://www.cppblog.com/API/comments/207436.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2014/06/27/207436.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/207436.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/207436.html</trackback:ping><description><![CDATA[<h3><a name="lua_newtable"><code><span style="font-size: 12pt;">lua_newtable</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">void lua_newtable (lua_State *L);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">创建一个空&nbsp;table ，并将之压入堆栈。 它等价于&nbsp;<code>lua_createtable(L, 0, 0)</code>&nbsp;。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><h3><a name="lua_gettop"><code><span style="font-size: 12pt;">lua_gettop</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">int lua_gettop (lua_State *L);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">返回栈顶元素的索引。 因为索引是从&nbsp;1 开始编号的， 所以这个结果等于堆栈上的元素个数（因此返回 0 表示堆栈为空）。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><strong><span style="font-size: 12pt;">luaL_newmetatable</span></strong></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 12pt;">int luaL_newmetatable (lua_State *L, const char *tname);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 12pt;">如果注册表中已经有Key为tname的数据则返回0. 否则创建一个新表作为userdata的metatable，并在注册表中注册它然后返回1. 不过两种情况都会把注册表中tname相关的值压入堆栈。</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"></p><h3><a name="luaL_checkudata"><code><span style="font-size: 12pt;">luaL_checkudata</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">void *luaL_checkudata (lua_State *L, int narg, const char *tname);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">Checks whether the function argument&nbsp;<code>narg</code>&nbsp;is a userdata of the type&nbsp;<code>tname</code>&nbsp;(see&nbsp;<a href="http://www.cnblogs.com/lancidie/admin/file:///E:/CunZhang/lua/lua_manual.html#luaL_newmetatable" style="color: #000000;"><code>luaL_newmetatable</code></a>).</p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"></p><h3><a name="lua_pushstring"><code><span style="font-size: 12pt;">lua_pushstring</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">void lua_pushstring (lua_State *L, const char *s);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">把指针&nbsp;<code>s</code>&nbsp;指向的以零结尾的字符串压栈。 Lua 对这个字符串做一次内存拷贝（或是复用一个拷贝）， 因此&nbsp;<code>s</code>&nbsp;处的内存在函数返回后，可以释放掉或是重用于其它用途。 字符串中不能包含有零字符；第一个碰到的零字符会认为是字符串的结束。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><h3><a name="lua_pushlstring"><code><span style="font-size: 12pt;">lua_pushlstring</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">void lua_pushlstring (lua_State *L, const char *s, size_t len);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">把指针&nbsp;<code>s</code>&nbsp;指向的长度为&nbsp;<code>len</code>&nbsp;的字符串压栈。 Lua 对这个字符串做一次内存拷贝（或是复用一个拷贝）， 因此&nbsp;<code>s</code>&nbsp;处的内存在函数返回后，可以释放掉或是重用于其它用途。 字符串内可以保存有零字符。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><h3><a name="lua_pushvalue"><code><span style="font-size: 12pt;">lua_pushvalue</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">void lua_pushvalue (lua_State *L, int index);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">把堆栈上给定有效处索引处的元素作一个拷贝压栈。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><h3><a name="lua_settable"><code><span style="font-size: 12pt;">lua_settable</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">void lua_settable (lua_State *L, int index);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">作一个等价于&nbsp;<code>t[k] = v</code>&nbsp;的操作， 这里&nbsp;<code>t</code>&nbsp;是一个给定有效索引&nbsp;<code>index</code>&nbsp;处的值，&nbsp;<code>v</code>&nbsp;指栈顶的值， 而&nbsp;<code>k</code>&nbsp;是栈顶之下的那个值。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">这个函数会把键和值都从堆栈中弹出。 和在 Lua 中一样，这个函数可能触发 "newindex" 事件的元方法 （参见&nbsp;<a href="http://www.cnblogs.com/lancidie/admin/file:///E:/CunZhang/lua/lua_manual.html#2.8" style="color: #000000;">&#167;2.8</a>）。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p><h3><a name="lua_pushcfunction"><code><span style="font-size: 12pt;">lua_pushcfunction</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">void lua_pushcfunction (lua_State *L, lua_CFunction f);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">将一个 C 函数压入堆栈。 这个函数接收一个 C 函数指针，并将一个类型为&nbsp;<code>function</code>&nbsp;的 Lua 值 压入堆栈。当这个栈定的值被调用时，将触发对应的 C 函数。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">注册到 Lua 中的任何函数都必须遵循正确的协议来接收参数和返回值 （参见&nbsp;<a href="http://www.cnblogs.com/lancidie/admin/file:///E:/CunZhang/lua/lua_manual.html#lua_CFunction" style="color: #000000;"><code>lua_CFunction</code></a>）。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><code>lua_pushcfunction</code>&nbsp;是作为一个宏定义出现的：</p><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;  #define lua_pushcfunction(L,f) lua_pushcclosure(L,f,0)</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><h3><a name="lua_setmetatable"><code><span style="font-size: 12pt;">lua_setmetatable</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">int lua_setmetatable (lua_State *L, int index);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">把一个 table 弹出堆栈，并将其设为给定索引处的值的 metatable 。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><h3><a name="lua_pushcclosure"><code><span style="font-size: 12pt;">lua_pushcclosure</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">把一个新的 C closure 压入堆栈。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">当创建了一个 C 函数后，你可以给它关联一些值，这样就是在创建一个 C closure （参见&nbsp;<a href="http://www.cnblogs.com/lancidie/admin/file:///E:/CunZhang/lua/lua_manual.html#3.4" style="color: #000000;">&#167;3.4</a>）； 接下来无论函数何时被调用，这些值都可以被这个函数访问到。 为了将一些值关联到一个 C 函数上， 首先这些值需要先被压入堆栈（如果有多个值，第一个先压）。 接下来调用&nbsp;<a href="http://www.cnblogs.com/lancidie/admin/file:///E:/CunZhang/lua/lua_manual.html#lua_pushcclosure" style="color: #000000;"><code>lua_pushcclosure</code></a>&nbsp;来创建出 closure 并把这个 C 函数压到堆栈上。 参数&nbsp;<code>n</code>&nbsp;告之函数有多少个值需要关联到函数上。&nbsp;<a href="http://www.cnblogs.com/lancidie/admin/file:///E:/CunZhang/lua/lua_manual.html#lua_pushcclosure" style="color: #000000;"><code>lua_pushcclosure</code></a>&nbsp;也会把这些值从栈上弹出。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><h3><a name="lua_newuserdata"><code><span style="font-size: 12pt;">lua_newuserdata</span></code></a></h3><pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; word-wrap: break-word; font-size: 12px; line-height: 18px; background-color: #ffffff;">void *lua_newuserdata (lua_State *L, size_t size);</pre><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">这个函数分配分配一块指定大小的内存块， 把内存块地址作为一个完整的 userdata 压入堆栈，并返回这个地址。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">userdata 代表 Lua 中的 C 值。 完整的 userdata 代表一块内存。 它是一个对象（就像 table 那样的对象）： 你必须创建它，它有着自己的元表，而且它在被回收时，可以被监测到。 一个完整的 userdata 只和它自己相等（在等于的原生作用下）。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">当 Lua 通过&nbsp;<code>gc</code>&nbsp;元方法回收一个完整的 userdata 时， Lua 调用这个元方法并把 userdata 标记为已终止。 等到这个 userdata 再次被收集的时候，Lua 会释放掉相关的内存。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><a name="lua_touserdata"><strong><span style="font-size: 12pt;">lua_touserdata</span></strong></a></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 12pt;">void *lua_touserdata (lua_State *L, int index);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 12pt;">如果给定索引处的值是一个完整的 userdata ，函数返回内存块的地址。 如果值是一个 light userdata ，那么就返回它表示的指针。 否则，返回&nbsp;</span><span style="font-size: 12pt;">NULL</span>&nbsp;<span style="font-size: 12pt;">。</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">Lua调用C++类要点：</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; margin-left: 18pt; text-indent: -18pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为此类建立一个全局表，表名为类名tbClass；</p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; text-indent: 18pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: #010001;">lua_newtable</span><span style="font-size: 9pt;">(<span style="color: #010001;">L</span>);</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; margin-left: 18pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: blue;">int</span><span style="font-size: 9pt;">&nbsp;<span style="color: #010001;">methods</span>&nbsp;=&nbsp;<span style="color: #010001;">lua_gettop</span>(<span style="color: #010001;">L</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; text-indent: 18pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: #010001;">lua_pushstring</span><span style="font-size: 9pt;">(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">T</span>::<span style="color: #010001;">className</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; text-indent: 18pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: #010001;">lua_pushvalue</span><span style="font-size: 9pt;">(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">methods</span>);</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; text-indent: 18pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: #010001;">lua_settable</span><span style="font-size: 9pt;">(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">LUA_GLOBALSINDEX</span>);</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">2．注册一个key为T::className的metatable，并制定其中的一些成员，用于之后生成的userdata。</p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; text-indent: 21pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: green;">//&nbsp;</span><span style="font-size: 9pt; color: green;">这个表用于userdata(T的对象)的metatable</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">luaL_newmetatable</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">T</span>::<span style="color: #010001;">className</span>);</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">int</span>&nbsp;<span style="color: #010001;">metatable</span>&nbsp;=&nbsp;<span style="color: #010001;">lua_gettop</span>(<span style="color: #010001;">L</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 9pt; color: green;">// metatable["__index"] = tbClass</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_pushliteral</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #a31515;">"__index"</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_pushvalue</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">methods</span>);</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_settable</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">metatable</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; text-indent: 21pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: green;">// metatable["__tostring"] = tostring_T</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_pushliteral</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #a31515;">"__tostring"</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_pushcfunction</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">tostring_T</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_settable</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">metatable</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: green;">// metatable["__gc"] = gc_T</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_pushliteral</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #a31515;">"__gc"</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_pushcfunction</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">gc_T</span>);</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_settable</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">metatable</span>);</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">3．&nbsp;为此表指定成员，每个成员的key为类的成员函数名，Value为一个带有闭包的统一函数。比如tbClass[FunName] = thunk，之后可以根据闭包得到具体是调用到哪个函数。闭包中有函数名和相应函数的组合结构(以lightuserdata的形式赋给闭包)。这些类成员函数参数都必须包括lua_State，因为它需要的参数都会在lua堆栈中。</p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: green;">//&nbsp;</span><span style="font-size: 9pt; color: green;">为tbClass填充成员函数</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">for</span>&nbsp;(<span style="color: #010001;">RegType</span>&nbsp;*<span style="color: #010001;">l</span>&nbsp;=&nbsp;<span style="color: #010001;">T</span>::<span style="color: #010001;">methods</span>;&nbsp;<span style="color: #010001;">l</span>-&gt;<span style="color: #010001;">name</span>;&nbsp;<span style="color: #010001;">l</span>++)</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: green;">/* edited by Snaily: shouldn't it be const RegType *l ... ? */</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_pushstring</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">l</span>-&gt;<span style="color: #010001;">name</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; margin-left: 42pt; text-indent: 21pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; margin-left: 42pt; text-indent: 21pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: green;">//&nbsp;</span><span style="font-size: 9pt; color: green;">把(函数名,函数地址)pair以lightuserdata的形式作为C closure的upvalue入栈</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_pushlightuserdata</span>(<span style="color: #010001;">L</span>, (<span style="color: blue;">void</span>*)<span style="color: #010001;">l</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; margin-left: 42pt; text-indent: 21pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; margin-left: 42pt; text-indent: 21pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: green;">//&nbsp;</span><span style="font-size: 9pt; color: green;">把一个新的C closure 压入堆栈。为upvalue的个数，并指定回调函数统一为thunk</span><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_pushcclosure</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">thunk</span>, 1); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; margin-left: 42pt; text-indent: 21pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; margin-left: 42pt; text-indent: 21pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: green;">// tbClass[FunName] = Function</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; margin-left: 42pt; text-indent: 21pt; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: #010001;">lua_settable</span><span style="font-size: 9pt;">(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">methods</span>);</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">4．创建C对象给脚本使用b = Account.new(Account, 30); new是tbClass下的一个函数(另外指定的，不会掉到thunk，这一句会调用到C的一个函数，里面会生成一个C对象，然后创建一个userdata&nbsp;用于关联到这个新生成的C对象。最后为这个userdata绑定上我们上面注册为T::classname的metatable。因为定制了metatable的__index成员，所以当userdata找不到的成员会去调用__index，因为之前我们把__index绑定到tbClass，所以也会调用到tbClass的相应成员。</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: green;">//&nbsp;</span></span><span style="font-size: 9pt; color: green;">创建一个新的T对象，并创建一个基于userdataType的userdata，其中保护了指向T对象的指针</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: blue;">int</span>&nbsp;<span style="color: #010001;">new_T</span>(<span style="color: #010001;">lua_State</span>&nbsp;*<span style="color: #010001;">L</span>)</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp; {</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_remove</span>(<span style="color: #010001;">L</span>, 1);&nbsp;&nbsp;&nbsp;<span style="color: green;">// use classname:new(), instead of classname.new()</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">T</span>&nbsp;*<span style="color: #010001;">obj</span>&nbsp;=&nbsp;<span style="color: blue;">new</span>&nbsp;<span style="color: #010001;">T</span>(<span style="color: #010001;">L</span>);&nbsp;<span style="color: green;">// call constructor for T objects</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">userdataType</span>&nbsp;*<span style="color: #010001;">ud</span>&nbsp;=</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">static_cast</span>&lt;<span style="color: #010001;">userdataType</span>*&gt;(<span style="color: #010001;">lua_newuserdata</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: blue;">sizeof</span>(<span style="color: #010001;">userdataType</span>)));</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">ud</span>-&gt;<span style="color: #010001;">pT</span>&nbsp;=&nbsp;<span style="color: #010001;">obj</span>;&nbsp;<span style="color: green;">// store pointer to object in userdata</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">luaL_getmetatable</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">T</span>::<span style="color: #010001;">className</span>);&nbsp;<span style="color: green;">// lookup metatable in Lua registry</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_setmetatable</span>(<span style="color: #010001;">L</span>, -2);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">return</span>&nbsp;1;&nbsp;<span style="color: green;">// userdata containing pointer to T object</span></span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp; }</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">5．&nbsp;当脚本中指定函数被调用的时候，比如b:deposit(50.30)的时候，b是userdata，它的metatable的__index和tbClass绑定(见4)，所以会调用到tbClass的相应成员，就是之前关联的thunk：这个时候L的堆栈里面有这个函数的两个参数，一个是b本身，一个是50.30。b是userdata，可以根据它取出对象的指针。见第4步。另外函数被调用的时候，它相关的upvalue也可以取得到，见步骤3。有了对象指针和相应的函数，调用也不为难了，记住参数50.30是保存在堆栈中传给类的成员函数来取得。</p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt; color: green;">//&nbsp;</span><span style="font-size: 9pt; color: green;">所有成员函数都会调用到这里，然后根据upvalue来执行具体的成员函数</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: blue;">int</span>&nbsp;<span style="color: #010001;">thunk</span>(<span style="color: #010001;">lua_State</span>&nbsp;*<span style="color: #010001;">L</span>)</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp; {</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: green;">// stack has userdata, followed by method args</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">T</span>&nbsp;*<span style="color: #010001;">obj</span>&nbsp;=&nbsp;<span style="color: #010001;">check</span>(<span style="color: #010001;">L</span>, 1);&nbsp;<span style="color: green;">// the object pointer from the table at index 0.</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">lua_remove</span>(<span style="color: #010001;">L</span>, 1);&nbsp;<span style="color: green;">// remove self so member function args start at index 1</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: green;">// get member function from upvalue</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">RegType</span>&nbsp;*<span style="color: #010001;">l</span>&nbsp;=&nbsp;<span style="color: blue;">static_cast</span>&lt;<span style="color: #010001;">RegType</span>*&gt;(<span style="color: #010001;">lua_touserdata</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">lua_upvalueindex</span>(1)));</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">return</span>&nbsp;(<span style="color: #010001;">obj</span>-&gt;*(<span style="color: #010001;">l</span>-&gt;<span style="color: #010001;">mfunc</span>))(<span style="color: #010001;">L</span>);&nbsp;<span style="color: green;">// call member function</span></span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp; }</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: green;">//&nbsp;</span></span><span style="font-size: 9pt; color: green;">根据指定位置narg获得对象指针,这个userdata是在new_T的时候创建的</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">static</span>&nbsp;<span style="color: #010001;">T</span>&nbsp;*<span style="color: #010001;">check</span>(<span style="color: #010001;">lua_State</span>&nbsp;*<span style="color: #010001;">L</span>,&nbsp;<span style="color: blue;">int</span>&nbsp;<span style="color: #010001;">narg</span>)</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp; {</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">void</span>&nbsp;*<span style="color: #010001;">pUserData</span>&nbsp;=&nbsp;<span style="color: #010001;">luaL_checkudata</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">narg</span>,&nbsp;<span style="color: #010001;">T</span>::<span style="color: #010001;">className</span>);&nbsp;&nbsp;&nbsp;</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">userdataType</span>&nbsp;*<span style="color: #010001;">ud</span>&nbsp;=&nbsp;<span style="color: blue;">static_cast</span>&lt;<span style="color: #010001;">userdataType</span>*&gt;(<span style="color: #010001;">pUserData</span>);&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: green;">//&nbsp;</span></span><span style="font-size: 9pt; color: green;">这个是函数的upvalue</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">if</span>(!<span style="color: #010001;">ud</span>)</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #010001;">luaL_typerror</span>(<span style="color: #010001;">L</span>,&nbsp;<span style="color: #010001;">narg</span>,&nbsp;<span style="color: #010001;">T</span>::<span style="color: #010001;">className</span>);</span></p><p align="left" style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: blue;">return</span>&nbsp;<span style="color: #010001;">ud</span>-&gt;<span style="color: #010001;">pT</span>;</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;"><span style="font-size: 9pt;">&nbsp;&nbsp;&nbsp;&nbsp; }</span></p><p style="font-size: 13px; margin-top: 10px; margin-bottom: 10px; font-family: Verdana, Helvetica, Arial; line-height: 18px; background-color: #ffffff;">&nbsp;</p><img src ="http://www.cppblog.com/API/aggbug/207436.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2014-06-27 15:34 <a href="http://www.cppblog.com/API/archive/2014/06/27/207436.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>lua5.1-&gt;lua5.0</title><link>http://www.cppblog.com/API/archive/2014/06/25/207409.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Wed, 25 Jun 2014 08:32:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2014/06/25/207409.html</guid><wfw:comment>http://www.cppblog.com/API/comments/207409.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2014/06/25/207409.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/207409.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/207409.html</trackback:ping><description><![CDATA[<div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">关键字：<br />　　and break do else elseif end false for function if in local nil not or repeat return then true until　while</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">使用变量不需要声明，总是全局变量，除非加"local"。local的作用域是在最里层的end和其配对的关键字之间。全局变量的作用域是整个程序。大小写相关。定义一个变量的方法就是赋值"＝"操作。变量类型，可以用type()函数来检查：<br />　　Nil&nbsp; 空值，所有没有使用过的变量都是nil。nil既是值又是类型。变量清除直接给变量赋以nil值。<br />　　Boolean&nbsp; 布尔值true 和 false。只有false和nil才被计算为false，而所有任何其它类型的值，都是true。比如0，空串等等，都是true。<br />　　Number&nbsp; 数值，相当于C语言的double实数如：4 0.4 4.57e-3 0.3e12 5e+20<br />　　Userdata&nbsp; 可以是宿主的任意数据类型，常用的有Struct和指针。<br />　　Thread　线程类型，在Lua中没有真正的线程，将一个函数分成几部份运行。<br />　　String&nbsp; 字符串，可以包含'/0'字符，可以定义很长的字符串。用双引号或单引号引用单行，"[["和"]]"引用多行字符串。新版支持"[==["和"]==]"多层标记，=号个数为层数。严格按层数匹配。支持一些转义字符：<br />/a铃/b退格/f换页/n换行/r回车/t制表符/v垂直制表//反斜杠/"双引号/'单引号/[左中括号/]右中括号<br />　　Table&nbsp; 关系表类型，功能强大。可以用除了nil任意类型的值来作数组的索引和内容。<br />　　Table的定义：T1 = {}&nbsp; T1[1]=10&nbsp; T1["John"]={Age=27, Gender="Male"}<br />　　　　这一句相当于T1["John"]["Gender"]="Male"<br />　　　　索引是字符串时可以简写成：T1.John.Gender="Male"或T1.John={Age=27, Gender="Male"}<br />　　　　第一，所有元素之间，总是用逗号"，"隔开；<br />　　　　第二，所有索引值都需要用"["和"]"括起来；如果是字符串，还可以去掉引号和中括号；<br />　　　　第三，如果不写索引，则索引就会被认为是数字，并按顺序自动从1往后编；<br />　　　　T1=<br />　　　　{<br />　　　　　　10,&nbsp; -- 相当于 [1] = 10<br />　　　　　　[100] = 40,<br />　　　　　　John=&nbsp; -- 如果你原意，你还可以写成：["John"] =<br />　　　　　　{<br />　　　　　　　　Age=27,&nbsp;&nbsp; -- 如果你原意，你还可以写成：["Age"] =27<br />　　　　　　　　Gender=Male&nbsp;&nbsp; -- 如果你原意，你还可以写成：["Gender"] ="Male"<br />　　　　　　},<br />　　　　　　20&nbsp; -- 相当于 [2] = 20<br />　　　　}</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">　　Function&nbsp; 函数也是一种类型，也就是说所有的函数本身就是一个变量。<br />函数的定义：function add(a,b) return a+b end 相当于add = function (a,b) return a+b end<br />如果函数只有一个参数，可以省略括号。<br />return语言一定要写在end之前。在中间放上return，写成：do return end。<br />函数可以接受可变参数个数，用"..."来定义function sum (a,b,...)<br />如 果想取得...所代表的参数，5.0版本可以在函数中访问arg局部变量（表类型）得到。如 sum(1,2,3,4)则，a = 1, b = 2, arg = {3, 4}，在5.1版本多了一个...变量（实际就是参数列表），区别只在于arg和...共同存在的情况，...会使arg变nil。<br />可以同时返回多个结果，比如：function s() return 1,2,3,4 end<br />　　　　a,b,c,d = s()&nbsp; -- 此时，a = 1, b = 2, c = 3, d = 4<br />使用面向对象编程：<br />　　　　t =　{ Age = 27, add = function(self, n) self.Age = self.Age+n end　}<br />　　　　print(t.Age)&nbsp; -- 27<br />　　　　t.add(t, 10) 可以简写成：t:add(10)<br />　　　　print(t.Age)&nbsp; -- 37</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br />单行注释"--"。只要--后面第一个字符不是多行字符串引用符[[，即为多行注释。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">语句之间可以用分号"；"隔开，也可以用空白隔开。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">条件控制：if 条件 then &#8230; elseif 条件 then &#8230; else &#8230; end</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">While循环：while 条件 do &#8230; end</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">Repeat循环：repeat &#8230; until 条件</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">For循环：for 变量 = 初值，终点值，步进 do &#8230; end<br />可以省略步进值，这时候，for循环会使用1作为步进值。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">For循环：for 变量1，变量2，&#8230; ，变量N in表或枚举函数 do &#8230; end</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">语句块用do 和 end 括起来的。可以在函数中和语句块中定局部变量。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">赋值语句可以同时给多个变量赋值。例如：a,b,c,d=1,2,3,4甚至是：a,b=b,a 方便的交换变量功能</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">默认变量总是全局的。定义局部变量，则在第一次赋值的时候用local说明。比如：<br />　　local a,b,c = 1,2,3&nbsp; -- a,b,c都是局部变量</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">数值运算支持 +, -, *, /,^,#,%。^表示指数乘方。比如2^3 结果为8。5.1版加了#长度运算符。字符串的长度单位为字节，表的长度为nil前的整数索引个数，也就是数组的个数，如果有名为n的索引，它的值就是长度。5.1版引进%模运算。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">用".."连接两个字符串。如："This a " .. "string." -- 等于 "this a string"</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">比较运算&lt; &gt; &lt;= &gt;= == ~=分别表示 小于，大于，不大于，不小于，相等，不相等。总是返回true或false。对于Table，Function和Userdata类型的数据，只有 == 和 ~=可以用。相等表示两个变量引用的是同一个数据。比如：　a={1,2}　　　　b=a　　　　print(a==b, a~=b)&nbsp; -- true, false<br />　　　　a={1,2}　　　　b={1,2}　　　　print(a==b, a~=b)&nbsp; -- false, true</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">逻辑运算and, or, not只有false和nil才计算为false，其它任何数据都计算为true，0也是true！<br />　　　　and 和 or的运算结果不是true和false，而是和它的两个操作数相关。<br />　　　　a and b：如果a为false，则返回a；否则返回b<br />　　　　a or b：如果 a 为true，则返回a；否则返回b</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">运算符优先级，从高到低顺序如下：<br />　　　　^<br />　　　　not - （一元运算）#<br />　　　　 * / %<br />　　　　 + -<br />　　　　 ..（字符串连接）<br />　　　　 &lt; &gt; &lt;= &gt;= ~= ==<br />　　　　 and<br />　　　　 or<br />　　　　 =</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">常用标准库函数:<br />print (&#183;&#183;&#183;)把所有参数打印出来，利用tostring (e)转换非字符。奇怪的是nil不能做..操作。<br />table.insert (table, [pos,] value)在pos位置插入一个值，默认是末尾。<br />table.remove (table [, pos])在pos位置删除一个值，默认是末尾。<br />table.concat (table [, sep [, i [, j]]])用sep来连接数组里从i到j字符串或数字并返回一个长字符串，默认用空串从1到末尾。如果j大于i，返回空串。<br />table.maxn (table)返回最大正数索引或0。<br />table.sort (table [, comp])对数组排序，排序函数默认是&lt;。<br />string.byte (s [, i [, j]])返回s串从i到j的数值。旧版只支持2个参数<br />string.char (&#183;&#183;&#183;)和byte函数功能相反，返回0或多个数字对应的字符串。<br />string.find (s, pattern [, init [, plain]])从s串中从init位置开始找到第一个匹配模式的子串位置，并返回起点和终点。plain如果为true，忽略模式。如果使用了捕获，则增加返回捕获的部分。<br />string.gmatch (s, pattern)这是一个迭代函数，每次返回一个匹配的串。旧版叫gfind。如果使用了捕获，则返回捕获的部分。<br />string.gsub (s, pattern, repl [, n])用rep1替换。n限制替换个数。%1-9表示被捕获的值。如果第3个参数是个函数并返回假，替换字符将保持原配而不是旧版的空串。<br />string.sub (s, i [, j])返回s从位置i到j的子串。负值表示从末尾往前数的位置。默认从1到末尾。<br />string.match (s, pattern [, init])从init匹配或捕获值返回。旧版没有这个函数。<br />string.format (formatstring, &#183;&#183;&#183;)格式化输出。%q可以输出安全字符串。<br />string.rep (s, n)把s复制n份<br />string.reverse (s)把s倒转。旧版没有这个函数。<br />string.len (s)计算字符串长度。<br />string.lower (s)小写化。string.upper (s)大写化。<br />io.read (&#183;&#183;&#183;)"*n"读一个数字，支持各种格式；"*a"读整个文件；"*l":读一行，默认；"n"读n个字符<br />io.write (&#183;&#183;&#183;)写字符或者数字<br />io.lines ([filename])迭代返回文件中的一行。<br />pairs (t)迭代返回表中的键值对<br />ipairs (t)迭代返回数组中的索引和值<br />module (name [, &#183;&#183;&#183;])创建一个模块。require (modname)加载一个模块</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">模式表：<br />.任意字符%w字母和数字%a字母%d数字%p标点字符%s空白符%大写字母表示相应集合的补集<br />%u大写字母%l小写字母%x十六进制数字%z代表0的字符%c控制字符<br />%是转义标识 []集合 ^补集<br />()表示捕获 %1-9是捕获值 %bxy是以xy为标识的对称结构<br />?匹配前一字符0次或1次 +匹配前一字符1次或多次<br />*最长匹配前一字符0次或多次 -最短匹配前一字符0次或多次<br />以^开头的模式只匹配目标串的开始部分，相似的，以$结尾的模式只匹配目标串的结尾部分。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">c调用lua函数一般的过程是:<br />1. load一个lua的文件，形成一个闭包并执行它<br />2. 在栈中压入函数的名称<br />3. 依次在栈中压入函数的实参<br />4. 使用lua_pcall调用lua函数。　形式是: lua_pcall(L, 参数个数,结果个数,　错误处理函数在栈中的索引)<br />&nbsp;&nbsp;&nbsp; 此时此函数相关的栈已经被清空。执行lua完毕后，如果成功，结果依次将压入栈中，　如果不成功，错误信息将 压入栈中<br />5. 从栈中读取返回结果或者错误信息。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">lua调用c函数(写成库的例子)<br />lua调用库在windows下是dll文件，在unix/linux下面是so文件<br />vs的过程如下：<br />1. 新建一个dll的工程<br />2. 定义一个def文件，定义dll的导出，mylib.def定义如下:<br />LIBRARY&nbsp; mylib.dll<br />DESCRIPTION "first dll for lua"<br />EXPORTS<br />luaopen_mylib<br />3. 编写库，新建一个cpp文件.<br />4. 定义库函数，这里以pil的lsin函数，输出传入参数的sin()值<br />5. 定义luaL_reg数组，这个是注册一系列公开给lua调用的函数数组. 数组最后一个元素必须是 {NULL, NULL} 的luaL_reg结构用来做结束标识.<br />6. 用luaL_openlib声明主函数</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">5.1版本和5.0版本的区别：<br />新模块系统，增量垃圾收集，varargs新机制，多行字符串或引用的新语法，#和%新操作符， metatable支持所有类型，使用luaconf.h来配置lua暂时避免版本冲突，完善的reentrant parser。Pil第二版包括了5.1的新内容，增加了新例子，对新模块系统，多状态和垃圾收集的详细阐述。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">语法：<br />函数传递可变参数用...来代替局部arg表。不使用...时，arg用法和旧版本一样；但使用...后（无论先后），局部arg都会变成nil。<br />在repeat.until里，局部变量的生命周期覆盖到until条件后面；<br />多行字符串或引用的新语法使用多层匹配代替以前的嵌套；<br />#和%新操作符。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">库函数：<br />string.gfind改为string.gmatch；<br />如果调用string.gsub的第3个参数是个函数，如果函数返回假，替换字符将保持原配而不是旧版的空串；<br />table.setn废弃，table.getn改为使用#；<br />loadlib改为package.loadlib；<br />math.mod改为math.fmod；<br />table.foreach和table.foreachi作废。可用for循环pairs或ipairs代替；<br />require从package.path而不是LUA_PATH得到path值；<br />collectgarbage (opt [, arg])参数从[limit]改为更多选择，gcinfo废弃改为collectgarbage("count")；<br />string.byte (s [, i [, j]])返回s串从i到j的数值。旧版只支持2个参数<br />string.match (s, pattern [, init])从init匹配或捕获值返回。旧版没有这个函数。<br />string.reverse (s)把s倒转。旧版没有这个函数。<br />module (name [, &#183;&#183;&#183;])创建一个模块。旧版没有这个函数。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">C API：<br />5.1版本增加了以luaL_开头的辅助库Auxiliary Library；<br />luaL_getn改为lua_objlen，luaL_setn废弃；<br />luaL_openlib改为luaL_register；<br />luaL_checkudata改为抛出异常而不是返回NULL。<br />luaopen_* functions不能直接调用，改为像调用其它普通c函数一样的过程；<br />lua_open改为lua_newstate，可以设置内存分配方法。luaL_newstate默认使用realloc分配方法；<br />5.0的调用方法：<br />&nbsp;lua_State *L = lua_open();<br />&nbsp;luaopen_base(L);<br />&nbsp;luaopen_string(L);<br />&nbsp;luaopen_math(L);<br />5.1的调用方法：<br />&nbsp;lua_State *L = luaL_newstate();<br />&nbsp;lua_cpcall(L, luaopen_base, 0);<br />&nbsp;lua_cpcall(L, luaopen_io, 0);<br />&nbsp;lua_cpcall(L, luaopen_math, 0);<br />&nbsp;lua_cpcall(L, luaopen_string, 0);<br />lua_pushcfunction(L, luaopen_*);lua_call();等价于lua_cpcall(L, luaopen_*, 0);</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">参考资料：<br />参考手册：<a href="http://www.lua.org/manual/5.x/" style="color: #336699; text-decoration: none;">http://www.lua.org/manual/5.x/</a><br />lua 5.1 win32解析器：<a href="http://luaforge.net/frs/download.php/2218/lua5_1_2_Win32_bin.zip" style="color: #336699; text-decoration: none;">http://luaforge.net/frs/download.php/2218/lua5_1_2_Win32_bin.zip</a><br />lua 5.1 VC++6.0 库：<a href="http://luaforge.net/frs/download.php/2241/lua5_1_2_Win32_vc6_lib.zip" style="color: #336699; text-decoration: none;">http://luaforge.net/frs/download.php/2241/lua5_1_2_Win32_vc6_lib.zip</a><br />luasocket 参考手册：<a href="http://www.cs.princeton.edu/~diego/professional/luasocket/reference.html" style="color: #336699; text-decoration: none;">http://www.cs.princeton.edu/~diego/professional/luasocket/reference.html</a><br />luasocket win32扩展包luasocket-2.0.1-lua5.1-win32下载：<a href="http://luaforge.net/frs/download.php/1618/luasocket-2.0.1-lua5.1-win32.zip" style="color: #336699; text-decoration: none;">http://luaforge.net/frs/download.php/1618/luasocket-2.0.1-lua5.1-win32.zip</a><br />tolua++ 参考手册：<a href="http://www.codenix.com/~tolua/tolua++.html" style="color: #336699; text-decoration: none;">http://www.codenix.com/~tolua/tolua++.html</a><br />tolua++ 1.0.92 源代码下载：<a href="http://www.codenix.com/~tolua/tolua++-1.0.92.tar.bz2" style="color: #336699; text-decoration: none;">http://www.codenix.com/~tolua/tolua++-1.0.92.tar.bz2</a></div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">其他经验：<br />lua的扩展库luasocket, luasql, luacom, kepler...</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">程序可以存成cpp也可以存成c, 如果以.c为扩展名就不需要加extern "C"</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">c和lua交互的时候，栈的编号是从1-n，也可以取负值，-1表示末尾</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">设置环境变量LUA_PATH="E:/LuaEdit/myproject/?.lua"，然后使用require "lua包/文件名"。然后就可以直接使用lua文件里的函数而不需要dofile(路径)了。在windows下的路径如果是/必须写成//，或者/。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">lua5.1win32的解析器下载来后可以直接使用。luasocketwin32扩展包下载后，需要正确设置LUA_PATH=&lt; LDIR&gt;/?.lua;?.lua和LUA_CPATH=&lt;CDIR&gt;/?.dll;?.dll。然后运行lua解析器， require相应的socket包就可以了。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">在VC++6下编译带lua的.dll文件的时候，在工程设置里必须指明LIBC.lib Libcmtd.lib的加载顺序。选择VC菜单Project-&gt;Settings-&gt;Link-&gt;Catagory然后在 Object/library&nbsp; Modules的Edit栏中填入LIBC.lib Libcmtd.lib。否则会出现：<br />Linking...<br />LIBC.lib(crt0dat.obj) : error LNK2005: __cinit already defined in LIBCMTD.lib(crt0dat.obj)</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">新版本下表迭带需要加pairs(t)，旧版本以下代码结果是正确的：<br />Lua 5.1.2&nbsp; Copyright (C) 1994-2007 Lua.org, PUC-Rio<br />&gt; function print_contents(t)<br />&gt;&gt; for k,v in t do<br />&gt;&gt; print(k .. "=" .. v)<br />&gt;&gt; end<br />&gt;&gt; end<br />&gt; print_contents{x=10, y=20}<br />stdin:2: attempt to call a table value<br />stack traceback:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stdin:2: in function 'print_contents'<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stdin:1: in main chunk<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [C]: ?</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">新版本中的...和arg不能同时出现，无论先后，...的出现都会使arg为nil：<br />print(#arg)<br />function test(...)<br />--print(...)<br />print(type(arg),#arg)<br />--print(...)<br />end<br />test(1,2,3,4)<br />print(#arg)</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">运行结果：<br />E:/lua5_1_2_Win32_bin&gt;lua5.1 e....lua 1 2 3<br />3<br />table&nbsp;&nbsp; 4<br />3<br />结果说明arg在新版本中还是可以使用的，但跟...冲突，跟全局表arg不冲突。但本地arg会覆盖全局的arg，如果两者都要调用该如何处理？使用...后，编译器仍然把函数里的arg看成是局部变量。因此变通的方法是：<br />print(#arg)<br />t=arg<br />function test(...)<br />print(...)<br />arg=t<br />print(type(arg),#arg)<br />--print(...)<br />end<br />test(1,2,3,4)<br />print(#arg)<br />这和旧版本是一样的。看来引入...的用意不是为了区分全局和局部的arg。那究竟是为了什么呢？？</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">lua安装：<br />Windows:&nbsp;&nbsp;<br />把etc目录下的luavs.bat 拷到lua的解压根目录下直接运行, 生成的.h .dll .lib .exe文件都在src下。<br />Linux:<br />$make linux &amp;&amp; make install 标准的linux安装</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br />在Windows XP SP2下使用Visual C++ 6. 编译lua的过程分为3步：<br />1，建立静态库工程，编译库文件<br />&nbsp;&nbsp;&nbsp;&nbsp; Lua库由标准库和核心库组成，我用的是5.1版本，所有代码都放在src目录中。把src目录中除lua.c,luac.c文件外所有的*.c文件添加到项目中，设置一下输出路径，F7编译就可以了。<br />2,建立Win32控制台工程 编译lua.exe Lua解释器<br />&nbsp;&nbsp; 把lua.c添加到工程中，link选项中包含进刚才编译好的lib文件，F7编译<br />3.再建立Win32控制台工程， 编译luac.exe&nbsp; Lua编译器<br />&nbsp;&nbsp; 同上步一样，编译成功后生成luac.exe， 最好把这两个文件放在新建的bin文件下，在添加进系统的环境变量。&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">tolua++在cygwin下不用SCons编译：<br />详见<a href="http://lua-users.org/wiki/CompilingToluappWithoutScons" style="color: #336699; text-decoration: none;">http://lua-users.org/wiki/CompilingToluappWithoutScons</a><br />src/lib下：<br />gcc -shared -o tolua++.dll *.c /usr/local/lib/lua51.dll -I../../include -I/usr/local/include<br />gcc -c *.c&nbsp; -I../../include -I/usr/local/include<br />ar rcsv libtolua++.a *.o<br />src/bin下：<br />gcc tolua.c toluabind.c -I../../include -I/usr/local/include -L /usr/local/lib -llua -L../lib/ -ltolua++<br />然后把所得到的文件复制到系统相应目录中。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">使用tolua用.pkg生成.cpp的时候，在生成的.cpp最前面设置#define TOLUA_API extern "C" __declspec(dllexport)可以使.dll文件导出时不改变文件名。貌似还要加<br />#ifndef __cplusplus#define __cplusplus#endif</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">使用cygwin产生的.dll文件不能被lua使用。用同一源文件在vc下生成的.dll文件是可以被lua用的。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">使用VC编译tolua时，把除了tolua.c和xxx.defalt以外的.c和.h都包含进去，然后在tolua++.h里设置 #define TOLUA_API extern "C" __declspec，不断得修改#include "tolua++.h"在各个文件中的位置，使得用dumpbin看到65个导出函数为止。貌似VC6版本太低不能成功设置预编译处理选项，因此这样麻烦 点。编译成功后就有.lib和.dll文件供接下来的.dll工程使用。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;"><br />extern "C" _declspec(dillexport)<br />extern "C" void DLL_EXPORT __stdcall</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">============<br />实际应用场景练习<br />============<br />一、利用Lua的Table实现类的多继承：<br />&nbsp;&nbsp;&nbsp; 1、假设基类为B1、B2<br />&nbsp;&nbsp;&nbsp; 2、继承的类为A<br />&nbsp;&nbsp;&nbsp; 3、使用的时候类似于：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instance1 = A:new()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instance1:Method1(arg1, arg2)<br />&nbsp;&nbsp;&nbsp; 这个不难，但是务必要掌握table的应用</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">答案：见OO.lua。在lua解析器下运行：dofile "OO.lua"</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">&nbsp;</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">二、利用lua的扩展包luasocket实现http的一个应用：<br />&nbsp;&nbsp;&nbsp; 1、构造http协议，访问<a href="http://www.qq.com/" style="color: #336699; text-decoration: none;">www.qq.com</a>，具体的访问方式网上有例子。<br />&nbsp;&nbsp;&nbsp; 2、在返回来的http包中，取出腾讯公司的客服电话号码 -- 需要使用到lua的字符串查找和模式匹配函数。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">答案：<br />下载lua5.1win32的解析器和luasocketwin32扩展包，正确设置LUA_PATH=&lt; LDIR&gt;/?.lua;?.lua和LUA_CPATH=&lt;CDIR&gt;/?.dll;?.dll，&lt;CDIR&gt;指向 luasocket-2.0.1-lua5.1-win32/lib，&lt;LDIR&gt;指向luasocket-2.0.1-lua5.1- win32/lua。lua程序见Phone.lua。在lua解析器下运行：dofile "Phone.lua"</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">----------------------------</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">http = require("socket.http")<br />qqweb = http.request("<a href="http://www.qq.com/" style="color: #336699; text-decoration: none;">http://www.qq.com</a>")<br />tel=string.match(qqweb,"腾讯客服电话：(%d+%-%d+)")<br />print("您要的电话号码是："..tel)</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">-------------------------------<br /><br />三、在Windows下，利用C++实现一个基本的Socket类库来给Lua使用：<br />&nbsp;&nbsp;&nbsp; 1、结合tolua++进行编译，生成Lua可以调用的dll文件，请参考网上的资料来熟悉tolua++的使用<br />&nbsp;&nbsp;&nbsp; 2、假设dll文件名为MySocket.dll，类为CMySocket，则调用的时候类似于：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; require("MySocket")<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instance1 = CMySocket:new()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instance2 = CMySocket:new()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instance1:Listen(9701)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instance2:Connect("127.0.0.1",9701)</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">答案：<br />windows下编译lua：<br />把etc目录下的luavs.bat 拷到lua的解压根目录下直接运行, 生成的.h .dll .lib .exe文件都在src下。<br />把相应的.h文件和lua51.lib文件拷贝到VC相应目录下。lua.exe和lua51.dll为lua解析器。<br />在cygwin下编译安装方法：$make linux &amp;&amp; make install</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">用cygwin编译安装tolua++，且不用SCons编译：<br />src/lib下：<br />动态链接文件：<br />gcc -shared -o tolua++.dll *.c /usr/local/lib/lua51.dll -I../../include -I/usr/local/include<br />静态连接文件：<br />gcc -c *.c&nbsp; -I../../include -I/usr/local/include<br />ar rcsv libtolua++.a *.o<br />src/bin下：<br />执行文件，改名为tolua++.exe：<br />gcc tolua.c toluabind.c -I../../include -I/usr/local/include -L /usr/local/lib -llua -L../lib/ -ltolua++<br />然后把所得到的文件复制到系统相应目录中。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">根据mysocket.h设计mysocket类模式，写成.pkg文件。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">产生binding文件mypkg.cpp备用，此时要用到mysocket.h：tolua++ -o mypkg.cpp mysocket.pkg<br />适当修改一下生成的mypkg.cpp文件，使以后导出的.dll文件函数名不变。<br />#define TOLUA_API extern "C" __declspec</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">用以下方法在cygwin下编译的.dll文件不能被lua使用，加载包会失败。<br />g++ -shared -o MySocket.dll *.cpp&nbsp; /usr/local/lib/lua51.dll -I/usr/local/include -I.. -L /usr/local/lib -ltolua++</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">改用VC来编译。先编译tolua++。<br />把src下除了tolua.c和toluabind_default.x以外的.c和.h都包 含进去。工程设置里要包含LIBC.lib Libcmtd.lib tolua.lib lua5.1.lib，include和lib路径也要包含lua的。然后设置#define TOLUA_API extern "C" __declspec编译成功后就有tolua.lib和tolua.dll文件供接下来的.dll工程使用。</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">把bingding文件mypkg.cpp和写好的mysocket.cpp，mysocket.h一起在VC下编译生成.dll文件。工程设 置里要包含LIBC.lib Libcmtd.lib tolua.lib lua51.lib，include和lib路径也要包含lua或tolua的。前面两个文件顺序一定不要写错，否则产生如下错误：<br />Linking...<br />LIBC.lib(crt0dat.obj) : error LNK2005: __cinit already defined in LIBCMTD.lib(crt0dat.obj)</div><div style="color: #333333; font-family: Arial; font-size: 14px; line-height: 26px; background-color: #ffffff;">编译产生的MySocket.dll文件就可以被lua调用了。<br />运行一个lua解析器程序实例，执行：<br />require("MySocket")<br />Instance1 = CMySocket:new()<br />Instance1:Listen(9701)<br />再运行另一个lua解析器程序实例，执行：<br />require("MySocket")<br />Instance2 = CMySocket:new()<br />Instance2:Connect("127.0.0.1",9701)</div><img src ="http://www.cppblog.com/API/aggbug/207409.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2014-06-25 16:32 <a href="http://www.cppblog.com/API/archive/2014/06/25/207409.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用c++与swig+lua</title><link>http://www.cppblog.com/API/archive/2014/04/24/206699.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Thu, 24 Apr 2014 08:12:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2014/04/24/206699.html</guid><wfw:comment>http://www.cppblog.com/API/comments/206699.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2014/04/24/206699.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/206699.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/206699.html</trackback:ping><description><![CDATA[1.下载swig,我这里用的是<span style="font-size: 14px;">swigwin-2.0.9.zip，官网地址</span><a href="http://www.swig.org/">http://www.swig.org/</a>&nbsp;载解压后，目录下有swig.exe程序<br />2. 在VS中新建工程TestLua<br />3.添加hello.h代码如下：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#ifndef&nbsp;HELLO_H__<br /><span style="color: #0000FF; ">#define</span>&nbsp;HELLO_H__<br /><br /><span style="color: #0000FF; ">int</span>&nbsp;sum(&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;a,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;b&nbsp;);<br /><span style="color: #0000FF; ">class</span>&nbsp;Test<br />{<br /><span style="color: #0000FF; ">public</span>:<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;a;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;b;<br />&nbsp;&nbsp;&nbsp;&nbsp;Test();<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;print();<br />};<br /><br /><span style="color: #0000FF; ">#endif</span>/*HELLO_H__*/</div><br />4.添加hello.cpp代码如下：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#include&nbsp;"stdafx.h"<br />#include&nbsp;"hello.h"<br /><br /><span style="color: #0000FF; ">int</span>&nbsp;sum(&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;a,&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;b&nbsp;)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;(a&nbsp;+&nbsp;b);<br />}<br />Test::Test()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;a&nbsp;=&nbsp;10;<br />&nbsp;&nbsp;&nbsp;&nbsp;b&nbsp;=&nbsp;20;<br />}<br /><span style="color: #0000FF; ">void</span>&nbsp;Test::print()<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;printf(&nbsp;"%d&nbsp;%d\n",&nbsp;a,&nbsp;b&nbsp;);<br />}</div><br />5.编写moduleh<span style="font-size: 14px;">ello.i文件,内容如下：<br /></span><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->%module&nbsp;hello<br />%{<br />#include&nbsp;"hello.h"<br />%}<br />%include&nbsp;"hello.h"</div><span style="font-size: 14px;"><br /></span>6.使用以下命令生成文件<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->swig.exe&nbsp;-c++&nbsp;-lua&nbsp;c:\modulehello.i</div>于是生成：<span style="font-size: 14px;">modulehello_wrap.cxx文件</span><br /><br />7.在工程包含<br /><div>C:\Program Files (x86)\Lua\5.1\include<br />符加库目录<span style="font-size: 14px;">"C:\Program Files (x86)\Lua\5.1\lib"<br />并且导入库</span><span style="font-size: 14px;">lua51.lib<br /><br /></span></div>8.在工程文件TestLua.cpp代码如下：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all">#include&nbsp;"stdafx.h"<br /><span style="color: #0000FF; ">extern</span>&nbsp;"C"<br />{<br />#include&nbsp;&lt;lua.h&gt;<br />#include&nbsp;&lt;lualib.h&gt;<br />#include&nbsp;&lt;lauxlib.h&gt;<br />};<br />#include&nbsp;"modulehello_wrap.cxx"<br /><span style="color: #0000FF; ">extern</span>&nbsp;"C"<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">extern</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;luaopen_hello(lua_State*&nbsp;L);&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;declare&nbsp;the&nbsp;wrapped&nbsp;module</span><span style="color: #008000; "><br /></span>};<br /><span style="color: #0000FF; ">int</span>&nbsp;_tmain(<span style="color: #0000FF; ">int</span>&nbsp;argc,&nbsp;_TCHAR*&nbsp;argv[])<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;lua_State&nbsp;*L;<br />&nbsp;&nbsp;&nbsp;&nbsp;L=lua_open();<br />&nbsp;&nbsp;&nbsp;&nbsp;luaopen_base(L);&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;load&nbsp;basic&nbsp;libs&nbsp;(eg.&nbsp;print)</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;luaopen_hello(L);&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;load&nbsp;the&nbsp;wrappered&nbsp;module</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(luaL_loadfile(L,"./hello.lua")==0)&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;load&nbsp;and&nbsp;run&nbsp;the&nbsp;file</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lua_pcall(L,0,0,0);<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">else</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("unable&nbsp;to&nbsp;load&nbsp;%s\n","hello.lua");<br />&nbsp;&nbsp;&nbsp;&nbsp;lua_close(L);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />}</div><br />9.编写lua脚本hello.lua如下：<br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->print(&nbsp;"测试脚本是否被调用"&nbsp;);<br />print(&nbsp;"hello"&nbsp;);<br />print(&nbsp;"hello,&nbsp;tpf"&nbsp;);<br />print(&nbsp;"看到hello的字样,表示脚本被调用"&nbsp;);<br /><br />print(&nbsp;"-----------------------------"&nbsp;);<br /><br />print(&nbsp;"下面测试函数"&nbsp;);<br />print(&nbsp;hello.sum(&nbsp;1,&nbsp;2&nbsp;)&nbsp;);<br />print(&nbsp;"看到数字表示函数正常被调用"&nbsp;);<br /><br />print(&nbsp;"-----------------------------"&nbsp;);<br /><br />print(&nbsp;"下面测试类调用"&nbsp;);<br />a&nbsp;=&nbsp;hello.Test();<br /><br />print(&nbsp;"-----------------------------"&nbsp;);<br />print(&nbsp;"成员变量&gt;&gt;&gt;",&nbsp;a.a&nbsp;);<br />print(&nbsp;"成员变量&gt;&gt;&gt;",&nbsp;a.b&nbsp;);<br /><br />print(&nbsp;"下面测试成员函数"&nbsp;);<br />a:print();<br />print(&nbsp;"看到数字表示成员函数被正常调用"&nbsp;);</div><br />10.得出结果如下：<br /><div>测试脚本是否被调用</div><div>hello</div><div>hello, tpf</div><div>看到hello的字样,表示脚本被调用</div><div>-----------------------------</div><div>下面测试函数</div><div>3</div><div>看到数字表示函数正常被调用</div><div>-----------------------------</div><div>下面测试类调用</div><div>-----------------------------</div><div>成员变量&gt;&gt;&gt; &nbsp; &nbsp; 10</div><div>成员变量&gt;&gt;&gt; &nbsp; &nbsp; 20</div><div>下面测试成员函数</div><div>10 20</div><div>看到数字表示成员函数被正常调用</div><img src ="http://www.cppblog.com/API/aggbug/206699.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2014-04-24 16:12 <a href="http://www.cppblog.com/API/archive/2014/04/24/206699.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++多线程调用python</title><link>http://www.cppblog.com/API/archive/2013/12/06/204618.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Fri, 06 Dec 2013 02:34:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2013/12/06/204618.html</guid><wfw:comment>http://www.cppblog.com/API/comments/204618.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2013/12/06/204618.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/204618.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/204618.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 脚本语言是快速编写富有弹性的代码的重要方法之一，在 Unix 系统自动化管理中已经应用了多种脚本语言。现在，在许多应用开发中，也提供了脚本层，这大大方便用户实现通用任务自动处理或者编写应用扩展，许多成功的应用，诸如 GIMP、Emacs、MS Office、PhotoShop、AutoCAD 等都应用了脚本技术。在某种意义上，一切皆可脚本化。在另一篇文章中，我们已经介绍了如何在 C 应用中嵌入...&nbsp;&nbsp;<a href='http://www.cppblog.com/API/archive/2013/12/06/204618.html'>阅读全文</a><img src ="http://www.cppblog.com/API/aggbug/204618.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2013-12-06 10:34 <a href="http://www.cppblog.com/API/archive/2013/12/06/204618.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++调用python函数</title><link>http://www.cppblog.com/API/archive/2013/12/06/204616.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Fri, 06 Dec 2013 02:02:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2013/12/06/204616.html</guid><wfw:comment>http://www.cppblog.com/API/comments/204616.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2013/12/06/204616.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/204616.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/204616.html</trackback:ping><description><![CDATA[<div>1.当取多个返回值时,如下：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" /><span style="color: #0000ff">def</span><span style="color: #000000">&nbsp;mix(a,&nbsp;b)&nbsp;:&nbsp;&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;r1&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;a&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;b&nbsp;&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;r2&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;a&nbsp;</span><span style="color: #000000">-</span><span style="color: #000000">&nbsp;b&nbsp;&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;(r1,&nbsp;r2)&nbsp;</span><span style="color: #008000">#</span><span style="color: #008000">&nbsp;(7,3)</span></div><br />c++代码如下：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><span style="color: #000000">#include </span><span style="color: #000000">"</span><span style="color: #000000">python.h</span><span style="color: #000000">"</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span><span style="color: #0000ff">int</span><span style="color: #000000"> _tmain(</span><span style="color: #0000ff">int</span><span style="color: #000000"> argc, _TCHAR</span><span style="color: #000000">*</span><span style="color: #000000"> argv[]) <br /><img id="Codehighlighter1_59_1101_Open_Image" onclick="this.style.display='none'; Codehighlighter1_59_1101_Open_Text.style.display='none'; Codehighlighter1_59_1101_Closed_Image.style.display='inline'; Codehighlighter1_59_1101_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_59_1101_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_59_1101_Closed_Text.style.display='none'; Codehighlighter1_59_1101_Open_Image.style.display='inline'; Codehighlighter1_59_1101_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_59_1101_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_59_1101_Open_Text"><span style="color: #000000">{ <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> </span><span style="color: #0000ff">string</span><span style="color: #000000"> filename </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #000000">"</span><span style="color: #000000">cal</span><span style="color: #000000">"</span><span style="color: #000000">; </span><span style="color: #008000">//</span><span style="color: #008000"> cal.py </span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /></span><span style="color: #000000"> </span><span style="color: #0000ff">string</span><span style="color: #000000"> methodname_mix </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #000000">"</span><span style="color: #000000">mix</span><span style="color: #000000">"</span><span style="color: #000000">; </span><span style="color: #008000">//</span><span style="color: #008000"> function name </span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /></span><span style="color: #000000"> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> Py_Initialize(); <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> </span><span style="color: #008000">//</span><span style="color: #008000"> load the module </span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /></span><span style="color: #000000"> PyObject </span><span style="color: #000000">*</span><span style="color: #000000"> pyFileName </span><span style="color: #000000">=</span><span style="color: #000000"> PyString_FromString(filename.c_str()); <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> PyObject </span><span style="color: #000000">*</span><span style="color: #000000"> pyMod </span><span style="color: #000000">=</span><span style="color: #000000"> PyImport_Import(pyFileName); <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> </span><span style="color: #008000">//</span><span style="color: #008000"> load the function </span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /></span><span style="color: #000000"> PyObject </span><span style="color: #000000">*</span><span style="color: #000000"> pyFunc_mix </span><span style="color: #000000">=</span><span style="color: #000000"> PyObject_GetAttrString(pyMod, methodname_mix.c_str()); <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> </span><span style="color: #008000">//</span><span style="color: #008000"> test the function is callable </span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /></span><span style="color: #000000"> </span><span style="color: #0000ff">if</span><span style="color: #000000"> (pyFunc_mix </span><span style="color: #000000">&amp;&amp;</span><span style="color: #000000"> PyCallable_Check(pyFunc_mix)) <br /><img id="Codehighlighter1_553_1052_Open_Image" onclick="this.style.display='none'; Codehighlighter1_553_1052_Open_Text.style.display='none'; Codehighlighter1_553_1052_Closed_Image.style.display='inline'; Codehighlighter1_553_1052_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_553_1052_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_553_1052_Closed_Text.style.display='none'; Codehighlighter1_553_1052_Open_Image.style.display='inline'; Codehighlighter1_553_1052_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif"> </span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_553_1052_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_553_1052_Open_Text"><span style="color: #000000">{ <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> PyObject </span><span style="color: #000000">*</span><span style="color: #000000"> pyParams </span><span style="color: #000000">=</span><span style="color: #000000"> PyTuple_New(</span><span style="color: #000000">2</span><span style="color: #000000">); <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> PyTuple_SetItem(pyParams, </span><span style="color: #000000">0</span><span style="color: #000000">, Py_BuildValue(</span><span style="color: #000000">"</span><span style="color: #000000">i</span><span style="color: #000000">"</span><span style="color: #000000">, </span><span style="color: #000000">5</span><span style="color: #000000">)); <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> PyTuple_SetItem(pyParams, </span><span style="color: #000000">1</span><span style="color: #000000">, Py_BuildValue(</span><span style="color: #000000">"</span><span style="color: #000000">i</span><span style="color: #000000">"</span><span style="color: #000000">, </span><span style="color: #000000">2</span><span style="color: #000000">)); <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> </span><span style="color: #008000">//</span><span style="color: #008000"> ok, call the function </span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /></span><span style="color: #000000"> </span><span style="color: #0000ff">int</span><span style="color: #000000"> r1 </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #000000">0</span><span style="color: #000000">, r2 </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #000000">0</span><span style="color: #000000">; <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> PyObject </span><span style="color: #000000">*</span><span style="color: #000000"> pyValue </span><span style="color: #000000">=</span><span style="color: #000000"> PyObject_CallObject(pyFunc_mix, pyParams); <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> PyArg_ParseTuple(pyValue, </span><span style="color: #000000">"</span><span style="color: #000000">i|i</span><span style="color: #000000">"</span><span style="color: #000000">, </span><span style="color: #000000">&amp;</span><span style="color: #000000">r1, </span><span style="color: #000000">&amp;</span><span style="color: #000000">r2); <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> </span><span style="color: #0000ff">if</span><span style="color: #000000"> (pyValue) <br /><img id="Codehighlighter1_967_1037_Open_Image" onclick="this.style.display='none'; Codehighlighter1_967_1037_Open_Text.style.display='none'; Codehighlighter1_967_1037_Closed_Image.style.display='inline'; Codehighlighter1_967_1037_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_967_1037_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_967_1037_Closed_Text.style.display='none'; Codehighlighter1_967_1037_Open_Image.style.display='inline'; Codehighlighter1_967_1037_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif"> </span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_967_1037_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_967_1037_Open_Text"><span style="color: #000000">{ <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> printf(</span><span style="color: #000000">"</span><span style="color: #000000">%d,%d\n</span><span style="color: #000000">"</span><span style="color: #000000">, r1, r2); </span><span style="color: #008000">//</span><span style="color: #008000">output is 7,3 </span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" /></span><span style="color: #000000"> }</span></span><span style="color: #000000"> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" /> }</span></span><span style="color: #000000"> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" />&nbsp;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> Py_Finalize(); <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> </span><span style="color: #0000ff">return</span><span style="color: #000000"> </span><span style="color: #000000">0</span><span style="color: #000000">; <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" />}</span></span></div><br />2.如果返回一个值时：<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #0000ff">import</span><span style="color: #000000"> string<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">def</span><span style="color: #000000"> AddMult(a, b):<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /> c </span><span style="color: #000000">=</span><span style="color: #000000"> a </span><span style="color: #000000">+</span><span style="color: #000000"> b<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /> </span><span style="color: #0000ff">print</span><span style="color: #000000"> c<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /> </span><span style="color: #0000ff">return</span><span style="color: #000000"> c</span></div><br /><br />c++代码如下：&nbsp;<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><span style="color: #000000">PyObject</span><span style="color: #000000">*</span><span style="color: #000000"> pModule </span><span style="color: #000000">=</span><span style="color: #000000">NULL;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> PyObject</span><span style="color: #000000">*</span><span style="color: #000000"> pFunc </span><span style="color: #000000">=</span><span style="color: #000000"> NULL;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> PyObject</span><span style="color: #000000">*</span><span style="color: #000000"> pArgs </span><span style="color: #000000">=</span><span style="color: #000000"> NULL;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> PyObject</span><span style="color: #000000">*</span><span style="color: #000000"> pRet </span><span style="color: #000000">=</span><span style="color: #000000"> NULL;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> Py_Initialize();<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> PyRun_SimpleString(</span><span style="color: #000000">"</span><span style="color: #000000">import sys</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> PyRun_SimpleString(</span><span style="color: #000000">"</span><span style="color: #000000">sys.path.append('./')</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> pModule </span><span style="color: #000000">=</span><span style="color: #000000"> PyImport_ImportModule(</span><span style="color: #000000">"</span><span style="color: #000000">httpsend</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> pFunc </span><span style="color: #000000">=</span><span style="color: #000000"> PyObject_GetAttrString(pModule, </span><span style="color: #000000">"</span><span style="color: #000000">AddMult</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #008000">//</span><span style="color: #008000">pArgs = Py_BuildValue("s, s", "This is ", "a python code");</span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span><span style="color: #000000"> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> pArgs </span><span style="color: #000000">=</span><span style="color: #000000"> Py_BuildValue(</span><span style="color: #000000">"</span><span style="color: #000000">ii</span><span style="color: #000000">"</span><span style="color: #000000">, </span><span style="color: #000000">12</span><span style="color: #000000">,</span><span style="color: #000000">34</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> <br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> pRet </span><span style="color: #000000">=</span><span style="color: #000000"> PyObject_CallObject(pFunc,pArgs);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #0000ff">int</span><span style="color: #000000"> pyResult</span><span style="color: #000000">=</span><span style="color: #000000">0</span><span style="color: #000000">,pyResult2 </span><span style="color: #000000">=</span><span style="color: #000000"> </span><span style="color: #000000">0</span><span style="color: #000000">;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #0000ff">char</span><span style="color: #000000"> </span><span style="color: #000000">*</span><span style="color: #000000">str;<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #0000ff">int</span><span style="color: #000000"> argRet </span><span style="color: #000000">=</span><span style="color: #000000"> PyArg_Parse(pRet,</span><span style="color: #000000">"</span><span style="color: #000000">i</span><span style="color: #000000">"</span><span style="color: #000000">, </span><span style="color: #000000">&amp;</span><span style="color: #000000">pyResult);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #0000ff">if</span><span style="color: #000000"> (argRet)<br /><img id="Codehighlighter1_555_579_Open_Image" onclick="this.style.display='none'; Codehighlighter1_555_579_Open_Text.style.display='none'; Codehighlighter1_555_579_Closed_Image.style.display='inline'; Codehighlighter1_555_579_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_555_579_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_555_579_Closed_Text.style.display='none'; Codehighlighter1_555_579_Open_Image.style.display='inline'; Codehighlighter1_555_579_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"> </span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_555_579_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_555_579_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> printf(</span><span style="color: #000000">"</span><span style="color: #000000">yes!\n</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" /> }</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #0000ff">else</span><span style="color: #000000"><br /><img id="Codehighlighter1_588_621_Open_Image" onclick="this.style.display='none'; Codehighlighter1_588_621_Open_Text.style.display='none'; Codehighlighter1_588_621_Closed_Image.style.display='inline'; Codehighlighter1_588_621_Closed_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_588_621_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_588_621_Closed_Text.style.display='none'; Codehighlighter1_588_621_Open_Image.style.display='inline'; Codehighlighter1_588_621_Open_Text.style.display='inline';" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif"> </span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_588_621_Closed_Text"><img alt="" src="http://www.cppblog.com/Images/dot.gif" /></span><span id="Codehighlighter1_588_621_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /> </span><span style="color: #008000">//</span><span style="color: #008000">错误</span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" /></span><span style="color: #000000"> printf(</span><span style="color: #000000">"</span><span style="color: #000000">error!\n</span><span style="color: #000000">"</span><span style="color: #000000">);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" /> }</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #0000ff">if</span><span style="color: #000000">(pModule)<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> Py_DECREF(pModule);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #0000ff">if</span><span style="color: #000000">(pFunc)<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> Py_DECREF(pFunc);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #0000ff">if</span><span style="color: #000000">(pArgs)<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> Py_DECREF(pArgs);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #0000ff">if</span><span style="color: #000000">(pRet)<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> Py_DECREF(pRet);<br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /> </span><span style="color: #008000">//</span><span style="color: #008000">PyGILState_Ensure();</span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" /></span><span style="color: #000000"> Py_Finalize();</span></div><br /><br /></div><img src ="http://www.cppblog.com/API/aggbug/204616.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2013-12-06 10:02 <a href="http://www.cppblog.com/API/archive/2013/12/06/204616.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>python 发送http post请求</title><link>http://www.cppblog.com/API/archive/2013/12/03/204566.html</link><dc:creator>C++技术中心</dc:creator><author>C++技术中心</author><pubDate>Tue, 03 Dec 2013 06:08:00 GMT</pubDate><guid>http://www.cppblog.com/API/archive/2013/12/03/204566.html</guid><wfw:comment>http://www.cppblog.com/API/comments/204566.html</wfw:comment><comments>http://www.cppblog.com/API/archive/2013/12/03/204566.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/API/comments/commentRss/204566.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/API/services/trackbacks/204566.html</trackback:ping><description><![CDATA[<div>1.新建http.py如下：
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;urllib<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;urllib2<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />url&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #800000">'</span><span style="color: #800000">http://push.hao123.com/apis/test_send_msg.php</span><span style="color: #800000">'</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />values&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;{</span><span style="color: #800000">'</span><span style="color: #800000">g_id</span><span style="color: #800000">'</span><span style="color: #000000">:</span><span style="color: #800000">'</span><span style="color: #800000">1027019902</span><span style="color: #800000">'</span><span style="color: #000000">,<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #800000">'</span><span style="color: #800000">m_time_to_send</span><span style="color: #800000">'</span><span style="color: #000000">:</span><span style="color: #800000">'</span><span style="color: #800000">1386049369</span><span style="color: #800000">'</span><span style="color: #000000">,<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #800000">'</span><span style="color: #800000">m_display</span><span style="color: #800000">'</span><span style="color: #000000">:</span><span style="color: #800000">'</span><span style="color: #800000">1</span><span style="color: #800000">'</span><span style="color: #000000">,<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #800000">'</span><span style="color: #800000">m_push_type</span><span style="color: #800000">'</span><span style="color: #000000">:</span><span style="color: #800000">'</span><span style="color: #800000">2</span><span style="color: #800000">'</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,</span><span style="color: #800000">'</span><span style="color: #800000">m_by_timezone</span><span style="color: #800000">'</span><span style="color: #000000">:</span><span style="color: #800000">'</span><span style="color: #800000">0</span><span style="color: #800000">'</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,</span><span style="color: #800000">'</span><span style="color: #800000">m_msg</span><span style="color: #800000">'</span><span style="color: #000000">:</span><span style="color: #800000">'</span><span style="color: #800000">中华人民共和国万岁</span><span style="color: #800000">'</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;,</span><span style="color: #800000">'</span><span style="color: #800000">mt_id</span><span style="color: #800000">'</span><span style="color: #000000">:</span><span style="color: #800000">'</span><span style="color: #800000">0</span><span style="color: #800000">'</span><span style="color: #000000">,<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #800000">'</span><span style="color: #800000">m_iggid_file</span><span style="color: #800000">'</span><span style="color: #000000">:</span><span style="color: #800000">'</span><span style="color: #800000">33600458</span><span style="color: #800000">'</span><span style="color: #000000"><br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />data&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;urllib.urlencode(values)<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">print</span><span style="color: #000000">&nbsp;data<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />req&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;urllib2.Request(url,&nbsp;data)<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />response&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;urllib2.urlopen(req)<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" />the_page&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;response.read()<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span><span style="color: #0000ff">print</span><span style="color: #000000">&nbsp;the_page<br /><img align="top" src="http://www.cppblog.com/images/OutliningIndicators/None.gif"  alt="" /></span></div><br />注意以下包含中文，需把文件另存为utf-8格式。<br />然后执行：python http.py</div><img src ="http://www.cppblog.com/API/aggbug/204566.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/API/" target="_blank">C++技术中心</a> 2013-12-03 14:08 <a href="http://www.cppblog.com/API/archive/2013/12/03/204566.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>