??xml version="1.0" encoding="utf-8" standalone="yes"?>久久99国产精品尤物,欧美伊人久久大香线蕉综合69,亚洲国产精品久久久久http://m.shnenglu.com/mmdengwo/zh-cnSat, 28 Jun 2025 16:27:26 GMTSat, 28 Jun 2025 16:27:26 GMT60C++中的q回g?/title><link>http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205819.html</link><dc:creator>沛沛</dc:creator><author>沛沛</author><pubDate>Mon, 17 Feb 2014 10:20:00 GMT</pubDate><guid>http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205819.html</guid><wfw:comment>http://m.shnenglu.com/mmdengwo/comments/205819.html</wfw:comment><comments>http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205819.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/mmdengwo/comments/commentRss/205819.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/mmdengwo/services/trackbacks/205819.html</trackback:ping><description><![CDATA[<span style="background-color: #eeeeee; color: #555555; font-family: Verdana, 'BitStream vera Sans', Tahoma, Helvetica, sans-serif; line-height: 20px;">原文<a style="color: #2970a6; text-decoration: none;">E序人生</a> >> <a style="color: #2970a6; text-decoration: none;">C++中的q回g?return value optimization)</a></span><span style="background-color: #eeeeee; color: #555555; font-family: Verdana, 'BitStream vera Sans', Tahoma, Helvetica, sans-serif; line-height: 20px;"><br />q回g化(Return Value OptimizationQ简URVOQ,是这么一U优化机Ӟ当函数需要返回一个对象的时候,如果自己创徏一个时对象用戯回,那么q个临时对象会消耗一个构造函敎ͼConstructorQ的调用、一个复制构造函数的调用QCopy ConstructorQ以及一个析构函敎ͼDestructorQ的调用的代仗而如果稍微做一点优化,可以将成本降低C个构造函数的代hQ下面是在Visual Studio 2008的Debug模式下做的一个测试:Q在GCC下测试的时候可能编译器自己q行了RVO优化Q看不到两种代码的区别)<br /><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 />--><span style="color: #008080; "> 1</span> <span style="color: #008000; ">//</span><span style="color: #008000; "> C++ Return Value Optimization<br /></span><span style="color: #008080; "> 2</span> <span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; "> 作者:代码疯子<br /></span><span style="color: #008080; "> 3</span> <span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; "> 博客Q?/span><span style="color: #008000; text-decoration: underline; ">http://www.programlife.net/</span><span style="color: #008000; "><br /></span><span style="color: #008080; "> 4</span> <span style="color: #008000; "></span>#include <iostream><br /><span style="color: #008080; "> 5</span> <span style="color: #0000FF; ">using</span> <span style="color: #0000FF; ">namespace</span> std;<br /><span style="color: #008080; "> 6</span>  <br /><span style="color: #008080; "> 7</span> <span style="color: #0000FF; ">class</span> Rational<br /><span style="color: #008080; "> 8</span> {<br /><span style="color: #008080; "> 9</span> <span style="color: #0000FF; ">public</span>:<br /><span style="color: #008080; ">10</span>     Rational(<span style="color: #0000FF; ">int</span> numerator = 0, <span style="color: #0000FF; ">int</span> denominator = 1) : <br /><span style="color: #008080; ">11</span>       n(numerator), d(denominator)<br /><span style="color: #008080; ">12</span>       {<br /><span style="color: #008080; ">13</span>           cout << "Constructor Called<img src="http://m.shnenglu.com/Images/dot.gif" alt="" />" << endl;<br /><span style="color: #008080; ">14</span>       }<br /><span style="color: #008080; ">15</span>       ~Rational()<br /><span style="color: #008080; ">16</span>       {<br /><span style="color: #008080; ">17</span>           cout << "Destructor Called<img src="http://m.shnenglu.com/Images/dot.gif" alt="" />" << endl;<br /><span style="color: #008080; ">18</span>       }<br /><span style="color: #008080; ">19</span>       Rational(<span style="color: #0000FF; ">const</span> Rational& rhs)<br /><span style="color: #008080; ">20</span>       {<br /><span style="color: #008080; ">21</span>           <span style="color: #0000FF; ">this</span>->d = rhs.d;<br /><span style="color: #008080; ">22</span>           <span style="color: #0000FF; ">this</span>->n = rhs.n;<br /><span style="color: #008080; ">23</span>           cout << "Copy Constructor Called<img src="http://m.shnenglu.com/Images/dot.gif" alt="" />" << endl;<br /><span style="color: #008080; ">24</span>       }<br /><span style="color: #008080; ">25</span>       <span style="color: #0000FF; ">int</span> numerator() <span style="color: #0000FF; ">const</span> { <span style="color: #0000FF; ">return</span> n; }<br /><span style="color: #008080; ">26</span>       <span style="color: #0000FF; ">int</span> denominator() <span style="color: #0000FF; ">const</span> { <span style="color: #0000FF; ">return</span> d; }<br /><span style="color: #008080; ">27</span> <span style="color: #0000FF; ">private</span>:<br /><span style="color: #008080; ">28</span>     <span style="color: #0000FF; ">int</span> n, d;<br /><span style="color: #008080; ">29</span> };<br /><span style="color: #008080; ">30</span>  <br /><span style="color: #008080; ">31</span> <span style="color: #008000; ">//</span><span style="color: #008000; ">const Rational operator*(const Rational& lhs,<br /></span><span style="color: #008080; ">32</span> <span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">                         const Rational& rhs)<br /></span><span style="color: #008080; ">33</span> <span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">{<br /></span><span style="color: #008080; ">34</span> <span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">    return Rational(lhs.numerator() * rhs.numerator(),<br /></span><span style="color: #008080; ">35</span> <span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">                    lhs.denominator() * rhs.denominator());<br /></span><span style="color: #008080; ">36</span> <span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">}</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">37</span> <span style="color: #008000; "></span> <br /><span style="color: #008080; ">38</span> <span style="color: #0000FF; ">const</span> Rational <span style="color: #0000FF; ">operator</span>*(<span style="color: #0000FF; ">const</span> Rational& lhs,<br /><span style="color: #008080; ">39</span>                          <span style="color: #0000FF; ">const</span> Rational& rhs)<br /><span style="color: #008080; ">40</span> {<br /><span style="color: #008080; ">41</span>     cout << "----------- Enter operator* -----------" << endl;<br /><span style="color: #008080; ">42</span>     Rational tmp(lhs.numerator() * rhs.numerator(),<br /><span style="color: #008080; ">43</span>         lhs.denominator() * rhs.denominator());<br /><span style="color: #008080; ">44</span>     cout << "----------- Leave operator* -----------" << endl;<br /><span style="color: #008080; ">45</span>     <span style="color: #0000FF; ">return</span> tmp;<br /><span style="color: #008080; ">46</span> }<br /><span style="color: #008080; ">47</span>  <br /><span style="color: #008080; ">48</span> <span style="color: #0000FF; ">int</span> main(<span style="color: #0000FF; ">int</span> argc, <span style="color: #0000FF; ">char</span> **argv)<br /><span style="color: #008080; ">49</span> {<br /><span style="color: #008080; ">50</span>     Rational x(1, 5), y(2, 9);<br /><span style="color: #008080; ">51</span>     Rational z = x * y;<br /><span style="color: #008080; ">52</span>     cout << "calc result: " << z.numerator() <br /><span style="color: #008080; ">53</span>         << "/" << z.denominator() << endl;<br /><span style="color: #008080; ">54</span>  <br /><span style="color: #008080; ">55</span>     <span style="color: #0000FF; ">return</span> 0;<br /><span style="color: #008080; ">56</span> }</div><span style="background-color: #eeeeee; color: #555555; font-family: Verdana, 'BitStream vera Sans', Tahoma, Helvetica, sans-serif; line-height: 20px;"><br /></span><p style="margin: 0px 0px 10px; color: #555555; font-family: Verdana, 'BitStream vera Sans', Tahoma, Helvetica, sans-serif; line-height: 20px; background-color: #eeeeee; padding: 0px;">函数输出截图如下Q?br /><a style="color: #2970a6; text-decoration: none;"><img src="http://www.programlife.net/wp-content/uploads/2011/06/non-rvo.jpg" alt="Return Value Optimization" title="non-rvo" width="667" height="233" size-full="" wp-image-1560"="" style="border: 0px; display: block; margin-left: auto; margin-right: auto; max-width: 723px;" /></a><br />可以看到消耗一个构造函敎ͼConstructorQ的调用、一个复制构造函数的调用QCopy ConstructorQ以及一个析构函敎ͼDestructorQ的调用的代仗?/p><p style="margin: 0px 0px 10px; color: #555555; font-family: Verdana, 'BitStream vera Sans', Tahoma, Helvetica, sans-serif; line-height: 20px; background-color: #eeeeee; padding: 0px;">而如果把operator*换成另一UŞ式:<br /><br /></p><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">1</span> <span style="color: #0000FF; ">const</span> Rational <span style="color: #0000FF; ">operator</span>*(<span style="color: #0000FF; ">const</span> Rational& lhs,<br /><span style="color: #008080; ">2</span>                 <span style="color: #0000FF; ">const</span> Rational& rhs)<br /><span style="color: #008080; ">3</span> {<br /><span style="color: #008080; ">4</span>     <span style="color: #0000FF; ">return</span> Rational(lhs.numerator() * rhs.numerator(),<br /><span style="color: #008080; ">5</span>                 lhs.denominator() * rhs.denominator());<br /><span style="color: #008080; ">6</span> }<br /><br /><br /><br /><span style="color: #555555; font-family: Verdana, 'BitStream vera Sans', Tahoma, Helvetica, sans-serif; font-size: 14px; line-height: 20px;">只会消耗一个构造函数的成本了:</span><br style="color: #555555; font-family: Verdana, 'BitStream vera Sans', Tahoma, Helvetica, sans-serif; font-size: 14px; line-height: 20px;" /><a style="color: #2970a6; text-decoration: none; font-family: Verdana, 'BitStream vera Sans', Tahoma, Helvetica, sans-serif; font-size: 14px; line-height: 20px;"><img src="http://www.programlife.net/wp-content/uploads/2011/06/rvo.jpg" alt="q回g? title="rvo" width="670" height="159" size-full="" wp-image-1561"="" style="border: 0px; display: block; margin-left: auto; margin-right: auto; max-width: 723px;" /></a></div><img src ="http://m.shnenglu.com/mmdengwo/aggbug/205819.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/mmdengwo/" target="_blank">沛沛</a> 2014-02-17 18:20 <a href="http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205819.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Copy On Write(写时复制)http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205812.html沛沛沛沛Mon, 17 Feb 2014 10:15:00 GMThttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205812.htmlhttp://m.shnenglu.com/mmdengwo/comments/205812.htmlhttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205812.html#Feedback0http://m.shnenglu.com/mmdengwo/comments/commentRss/205812.htmlhttp://m.shnenglu.com/mmdengwo/services/trackbacks/205812.html本文最初发表于E序人生 >> Copy On Write(写时复制) 作者:代码疯子

Copy On WriteQ写时复Ӟ是在~程中比较常见的一个技术,面试中也会偶出玎ͼ好像Java中就l常有字W串写时复制的笔试题Q,今天在看《More Effective C++》的引用计数时就讲到了Copy On Write——写时复制。下面简单介l下Copy On Write(写时复制)Q我们假设STL中的string支持写时复制Q只是假设,具体未经考证Q这里以Mircosoft Visual Studio 6.0ZQ如果有兴趣Q可以自q阅源码)

Copy On Write(写时复制)的原理是什么?
有一定经验的E序员应该都知道Copy On Write(写时复制)使用?#8220;引用计数”Q会有一个变量用于保存引用的数量。当W一个类构造时Qstring的构造函CҎ传入的参C堆上分配内存Q当有其它类需要这块内存时Q这个计Cؓ自动累加Q当有类析构Ӟq个计数会减一Q直到最后一个类析构Ӟ此时的引用计Cؓ1或是0Q此ӞE序才会真正的Freeq块从堆上分配的内存?br />引用计数是stringcM写时才拷贝的原理Q?/p>

什么情况下触发Copy On Write(写时复制)
很显Ӟ当然是在׃n同一块内存的cd生内Ҏ变时Q才会发生Copy On Write(写时复制)。比如stringcȝ[]??=?{,q有一些stringcM诸如insert、replace、append{成员函数等Q包括类的析构时?/p>

CZ代码Q?br />

// 作者:代码疯子 
// 博客Qhttp://www.programlife.net/
// 引用计数 & 写时复制
#include <iostream>
#include <string>
using namespace std;  
int main(int argc, char **argv)
{
   string sa = "Copy on write";
   string sb = sa;
   string sc = sb;
   printf("sa char buffer address: 0x%08X\n", sa.c_str());
   printf("sb char buffer address: 0x%08X\n", sb.c_str());
   printf("sc char buffer address: 0x%08X\n", sc.c_str());  
   sc = "Now writing..."; printf("After writing sc:\n");
   printf("sa char buffer address: 0x%08X\n", sa.c_str());
   printf("sb char buffer address: 0x%08X\n", sb.c_str());
   printf("sc char buffer address: 0x%08X\n", sc.c_str());  
   return 0;
}
输出l果如下QVC 6.0Q:

Copy On WriteQ写时复Ӟ
可以看到QVC6里面的string是支持写时复制的Q但是我的Visual Studio 2008׃支持q个Ҏ(Debug和Release都是Q:
Visual Studio 2008不支持Copy On WriteQ写时复Ӟ

拓展阅读Q(摘自《Windows Via C/C++?th EditionQ不想看英文可以看中文的PDFQ中文版W?42)
Static Data Is Not Shared by Multiple Instances of an Executable or a DLL



沛沛 2014-02-17 18:15 发表评论
]]>
Linux安装CodeBlocksSVN最新版http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205810.html沛沛沛沛Mon, 17 Feb 2014 10:10:00 GMThttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205810.htmlhttp://m.shnenglu.com/mmdengwo/comments/205810.htmlhttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205810.html#Feedback0http://m.shnenglu.com/mmdengwo/comments/commentRss/205810.htmlhttp://m.shnenglu.com/mmdengwo/services/trackbacks/205810.htmlhttp://apt.jenslody.de/



# 打开软g源配|文件添加下??/span>
sudo gedit /etc/apt/sources.list

deb http://apt.jenslody.de/ any main
deb-src http://apt.jenslody.de/ any main
deb http://apt.jenslody.de/ any release
deb-src http://apt.jenslody.de/ any release
deb http://apt.wxwidgets.org/ lenny-wx main

# 更新软g源配|文??安装Key
sudo apt-get update
sudo apt-get install jens-lody-debian-keyring
wget -q http://apt.wxwidgets.org/key.asc -O- | sudo apt-key add -


q样只是把Y件源家进MQƈ没有安装好,所以还要输入安装命?/span>
# 然后输入下面q个命o开始安?codeblocks
sudo apt-get install codeblocks



现在安装好,从编EY仉开启CodeBlocks了,是英文的Qƈ且是最q几日的最版本


# 你也可以直接下蝲 CodeBlocks 的二q制发行包,从这个URLq入
http://apt.jenslody.de/pool/


# 中文化CodeBlocks 下蝲q个包,语言文g Linux下通用?/span>
http://srgb.googlecode.com/files/CodeBlocks_Linux_Install.zip

q入压羃包把语言文g攑ֈ桌面 '/locale/zh_CN/CodeBlocks.mo'  
中文?codeblocks locale/zh_CN/codeblocks.mo 里的 中文化文件放q里
 '/usr/share/codeblocks/locale/zh_CN/codeblocks.mo'  
讄权限为所有h可以讉K




# 使用理员权限把 语言?locale 目录 拉到 /usr/share/codeblocks?/span>
sudo nautilus /usr/share/codeblocks/
注意 locale 的权限可能不完整Q所?选住目录 所有?组-其他讑֮都能讉K文g;
对包含的文g应用权限Q?/span>
q入 /usr/share/codeblocks/locale/zh_CN/ 目录选两个文?/span>
右键修改权限 所有??组 都可以读?/span>




现在安装?CodeBlocks 打开是中文里Q但是只有基本IDE环境Q很多插件和开发包没安?/span>
可以输入 sudo apt-get install codeblocks <按两下TAB>
列出没有安装的其他包Q?你可以选择安装Q我h?/span>
sudo apt-get install codeblocks* <回R>
sudo apt-get install libwxsmith* <回R>
sudo apt-get install libwxgtk2.8-dev <回R>


现在开启CBQ徏立一个wx目Q编译,可以~译成功?/span>


沛沛 2014-02-17 18:10 发表评论
]]>
Step By Step(userdata)http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205809.html沛沛沛沛Mon, 17 Feb 2014 09:50:00 GMThttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205809.htmlhttp://m.shnenglu.com/mmdengwo/comments/205809.htmlhttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205809.html#Feedback0http://m.shnenglu.com/mmdengwo/comments/commentRss/205809.htmlhttp://m.shnenglu.com/mmdengwo/services/trackbacks/205809.html   在Lua中可以通过自定义类型的方式与C语言代码更高效、更灉|的交互。这里我们通过一个简单完整的CZ来学习一下Lua中userdata的用方式。需要说明的是,该示例完全来自于Programming in Lua。其功能是用CE序实现一个Lua的布数l,以提供程序的执行效率。见下面的代码和关键性注释?  

复制代码
  1 #include <lua.hpp>   
2
#include <lauxlib.h>
3
#include <lualib.h>
4
#include <limits.h>
5

6
#define BITS_PER_WORD (CHAR_BIT * sizeof(int))
7
#define I_WORD(i) ((unsigned int)(i))/BITS_PER_WORD
8
#define I_BIT(i) (1 << ((unsigned int)(i)%BITS_PER_WORD))
9

10
typedef struct NumArray {
11
int size; 12 unsigned int values[1];
13
} NumArray;
14

15
extern "C" int newArray(lua_State* L)
16
{
17
//1. 查第一个参数是否ؓ整型。以及该参数的值是否大于等?.
18
int n = luaL_checkint(L,1);
19
luaL_argcheck(L, n >= 1, 1, "invalid size.");
20
size_t nbytes = sizeof(NumArray) + I_WORD(n - 1) * sizeof(int);
21
//2. 参数表示Lua为userdata分配的字节数。同时将分配后的userdata对象压入栈中?/span>
22
NumArray* a = (NumArray*)lua_newuserdata(L,nbytes);
23
a->size = n;
24
for (int i = 0; i < I_WORD(n - 1); ++i)
25
a->values[i] = 0;
26
//获取注册表变量myarrayQ该key的gؓmetatable?/span>
27
luaL_getmetatable(L,"myarray");
28
//userdata的元表设|ؓ和myarray兌的table。同时将栈顶元素弹出?/span>
29
lua_setmetatable(L,-2);
30
return 1;
31
}
32

33
extern "C" int setArray(lua_State* L)
34
{
35
//1. Lua传给该函数的W一个参数必LuserdataQ该对象的元表也必须是注册表中和myarray兌的table?
36
//否则该函数报错ƈl止E序?/span>
37
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
38
int index = luaL_checkint(L,2) - 1;
39
//2. ׃Mcd的数据都可以成ؓ布尔|因此q里使用any只是Z保?个参数?/span>
40
luaL_checkany(L,3);
41
luaL_argcheck(L,a != NULL,1,"'array' expected.");
42
luaL_argcheck(L,0 <= index && index < a->size,2,"index out of range.");
43
if (lua_toboolean(L,3))
44
a->values[I_WORD(index)] |= I_BIT(index);
45
else
46
a->values[I_WORD(index)] &= ~I_BIT(index);
47
return 0;
48
}
49

50
extern "C" int getArray(lua_State* L)
51
{
52
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
53
int index = luaL_checkint(L,2) - 1;
54
luaL_argcheck(L, a != NULL, 1, "'array' expected.");
55
luaL_argcheck(L, 0 <= index && index < a->size,2,"index out of range");
56
lua_pushboolean(L,a->values[I_WORD(index)] & I_BIT(index));
57
return 1;
58
}
59

60
extern "C" int getSize(lua_State* L)
61
{
62
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
63
luaL_argcheck(L,a != NULL,1,"'array' expected.");
64
lua_pushinteger(L,a->size);
65
return 1;
66
}
67

68
extern "C" int array2string(lua_State* L)
69
{
70
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
71
lua_pushfstring(L,"array(%d)",a->size);
72
return 1;
73
}
74

75
static luaL_Reg arraylib_f [] = {
76
{"new", newArray},
77
{NULL, NULL}
78
};
79

80
static luaL_Reg arraylib_m [] = {
81
{"set", setArray},
82
{"get", getArray},
83
{"size", getSize},
84
{"__tostring", array2string}, //print(a)时Lua会调用该元方法?/span>
85
{NULL, NULL}
86
};
87

88
extern "C" __declspec(dllexport)
89
int luaopen_testuserdata(lua_State* L)
90
{
91
//1. 创徏元表Qƈ该元表指定lnewArray函数新创建的userdata。在Lua中userdata也是以table的n份表现的?
92
//q样在调用对象函数时Q可以通过验证其metatable的名U来定参数userdata是否合法?/span>
93
luaL_newmetatable(L,"myarray");
94
lua_pushvalue(L,-1);
95 //2. Z实现面对对象的调用方式,需要将元表的__index字段指向自nQ同时再arraylib_m数组中的函数注册?
96
//元表中,之后Zq些注册函数的调用就可以以面向对象的形式调用了?
97
//lua_setfield在执行后会将栈顶的table弹出?/span>
98
lua_setfield(L,-2,"__index");
99
//这些成员函数注册给元表Q以保证Lua在寻找方法时可以定位。NULL参数表示用栈顶的table代替W二个参数?/span>
100 luaL_register(L,NULL,arraylib_m);
101 //q里只注册的工厂Ҏ?/span>
102 luaL_register(L,"testuserdata",arraylib_f);
103 return 1;
104 }
复制代码

  轻量UuserdataQ?nbsp;
  之前介绍的是full userdataQLuaq提供了另一U轻量userdata(light userdata)。事实上Q轻量userdata仅仅表示的是C指针的|?void*)。由于它只是一个|所以不用创建。如果需要将一个轻量userdata攑օ栈中Q调用lua_pushlightuserdata卛_。full userdata和light userdata之间最大的区别来自于相{性判断,对于一个full userdataQ它只是与自w相{,而light userdata则表CZؓ一个C指针Q因此,它与所有表C同一指针的light userdata相等。再有就是light userdata不会受到垃圾攉器的理Q用时像一个普通的整型数字一栗?/p>

沛沛 2014-02-17 17:50 发表评论
]]>
Step By Step(~写C函数的技?http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205808.html沛沛沛沛Mon, 17 Feb 2014 09:45:00 GMThttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205808.htmlhttp://m.shnenglu.com/mmdengwo/comments/205808.htmlhttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205808.html#Feedback0http://m.shnenglu.com/mmdengwo/comments/commentRss/205808.htmlhttp://m.shnenglu.com/mmdengwo/services/trackbacks/205808.html阅读全文

沛沛 2014-02-17 17:45 发表评论
]]>
Step By Step(Lua调用C函数)http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205807.html沛沛沛沛Mon, 17 Feb 2014 09:45:00 GMThttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205807.htmlhttp://m.shnenglu.com/mmdengwo/comments/205807.htmlhttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205807.html#Feedback0http://m.shnenglu.com/mmdengwo/comments/commentRss/205807.htmlhttp://m.shnenglu.com/mmdengwo/services/trackbacks/205807.html Lua可以调用C函数的能力将极大的提高Lua的可扩展性和可用性。对于有些和操作pȝ相关的功能,或者是Ҏ率要求较高的模块Q我们完全可以通过C函数来实玎ͼ之后再通过Lua调用指定的C函数。对于那些可被Lua调用的C函数而言Q其接口必须遵@Lua要求的Ş式,?span style="color: #0000ff;">typedef int (*lua_CFunction)(lua_State* L)。简单说明一下,该函数类型仅仅包含一个表CLua环境的指针作为其唯一的参敎ͼ实现者可以通过该指针进一步获取Lua代码中实际传入的参数。返回值是整型Q表CC函数返回给Lua代码的返回值数量,如果没有q回|则return 0卛_。需要说明的是,C函数无法直接真正的q回D回给Lua代码Q而是通过虚拟栈来传递Lua代码和C函数之间的调用参数和q回值的。这里我们将介绍两种Lua调用C函数的规则?br />    1. C函数作ؓ应用E序的一部分?/span>

复制代码
1 #include <stdio.h>  
2
#include <string.h>
3
#include <lua.hpp>
4
#include <lauxlib.h>
5
#include <lualib.h>
6

7
//待Lua调用的C注册函数?/span>
8
static int add2(lua_State* L)
9
{
10 //查栈中的参数是否合法Q?表示Lua调用时的W一个参?从左到右)Q依此类推?
11 //如果Lua代码在调用时传递的参数不ؓnumberQ该函数报错ƈl止E序的执行?/span>
12 double op1 = luaL_checknumber(L,1);
13 double op2 = luaL_checknumber(L,2);
14 //函数的l果压入栈中。如果有多个q回|可以在这里多ơ压入栈中?/span>
15 lua_pushnumber(L,op1 + op2);
16 //q回值用于提CC函数的返回值数量,卛_入栈中的q回值数量?/span>
17 return 1;
18 }
19
20 //另一个待Lua调用的C注册函数?/span>
21 static int sub2(lua_State* L)
22 {
23 double op1 = luaL_checknumber(L,1);
24 double op2 = luaL_checknumber(L,2);
25 lua_pushnumber(L,op1 - op2);
26 return 1;
27 }
28
29 const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";
30
31 int main()
32 {
33 lua_State* L = luaL_newstate();
34 luaL_openlibs(L);
35 //指定的函数注册为Lua的全局函数变量Q其中第一个字W串参数为Lua代码
36 //在调用C函数时用的全局函数名,W二个参Cؓ实际C函数的指针?/span>
37 lua_register(L, "add2", add2);
38 lua_register(L, "sub2", sub2);
39 //在注册完所有的C函数之后Q即可在Lua的代码块中用这些已l注册的C函数了?/span>
40 if (luaL_dostring(L,testfunc))
41 printf("Failed to invoke.\n");
42 lua_close(L); 43 return 0; 44 }
复制代码

    2. C函数库成为Lua的模块?/span>
    包含C函数的代码生成库文gQ如Linux的soQ或Windows的DLLQ同时拷贝到Lua代码所在的当前目录Q或者是LUA_CPATH环境变量所指向的目录,以便于Lua解析器可以正定位到他们。在我当前的Windowspȝ中,我将其copy?C:\Program Files\Lua\5.1\clibs\"Q这里包含了所有Lua可调用的C库。见如下C语言代码和关键性注释:

复制代码
1 #include <stdio.h>  
2
#include <string.h>
3
#include <lua.hpp>
4
#include <lauxlib.h>
5
#include <lualib.h>
6

7
//待注册的C函数Q该函数的声明Ş式在上面的例子中已经l出?
8
//需要说明的是,该函数必MC的Ş式被导出Q因此extern "C"是必ȝ?
9
//函数代码和上例相同,q里不再赘述?/span>
10 extern "C" int add(lua_State* L)
11 { 12 double op1 = luaL_checknumber(L,1);
13 double op2 = luaL_checknumber(L,2);
14 lua_pushnumber(L,op1 + op2);
15 return 1;
16 }
17
18 extern "C" int sub(lua_State* L)
19 {
20 double op1 = luaL_checknumber(L,1);
21 double op2 = luaL_checknumber(L,2);
22 lua_pushnumber(L,op1 - op2);
23 return 1;
24 }
25
26 //luaL_Regl构体的W一个字Dؓ字符Ԍ在注册时用于通知Lua该函数的名字?
27 //W一个字DؓC函数指针?
28 //l构体数l中的最后一个元素的两个字段均ؓNULLQ用于提CLua注册函数已经到达数组的末?/span>
29 static luaL_Reg mylibs[] = {
30 {"add", add},
31 {"sub", sub},
32 {NULL, NULL}
33 };
34
35 //该C库的唯一入口函数。其函数{֐{同于上面的注册函数。见如下几点说明Q?
36 //1. 我们可以该函数单的理解为模块的工厂函数?
37 //2. 其函数名必须为luaopen_xxxQ其中xxx表示library名称。Lua代码require "xxx"需要与之对应?
38 //3. 在luaL_register的调用中Q其W一个字W串参数为模块名"xxx"Q第二个参数为待注册函数的数l?
39 //4. 需要强调的是,所有需要用?xxx"的代码,不论Cq是LuaQ都必须保持一_q是Lua的约定,
40 // 否则无法调用?/span>
41 extern "C" __declspec(dllexport)
42 int luaopen_mytestlib(lua_State* L)
43 {
44 const char* libName = "mytestlib";
45 luaL_register(L,libName,mylibs);
46 return 1;
47 }
复制代码

    见如下Lua代码Q?/p>

1 require "mytestlib"  --指定包名U?/span> 
2
3 --在调用时Q必Lpackage.function
4 print(mytestlib.add(1.0,2.0))
5 print(mytestlib.sub(20.1,19))


沛沛 2014-02-17 17:45 发表评论
]]>
Step By Step(C调用Lua)http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205806.html沛沛沛沛Mon, 17 Feb 2014 09:44:00 GMThttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205806.htmlhttp://m.shnenglu.com/mmdengwo/comments/205806.htmlhttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205806.html#Feedback0http://m.shnenglu.com/mmdengwo/comments/commentRss/205806.htmlhttp://m.shnenglu.com/mmdengwo/services/trackbacks/205806.html阅读全文

沛沛 2014-02-17 17:44 发表评论
]]>
Step By Step(Lua-C API?http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205805.html沛沛沛沛Mon, 17 Feb 2014 09:44:00 GMThttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205805.htmlhttp://m.shnenglu.com/mmdengwo/comments/205805.htmlhttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205805.html#Feedback0http://m.shnenglu.com/mmdengwo/comments/commentRss/205805.htmlhttp://m.shnenglu.com/mmdengwo/services/trackbacks/205805.html   Lua是一U嵌入式脚本语言Q即Lua不是可以单独q行的程序,在实际应用中Q主要存在两U应用Ş式。第一UŞ式是QC/C++作ؓȝ序,调用Lua代码Q此时可以将Lua看做“可扩展的语言”Q我们将q种应用UCؓ“应用E序代码”。第二种形式是Luah控制权,而C/C++代码则作为Lua?#8220;库代?#8221;。在q两UŞ式中Q都是通过Lua提供的C API完成两种语言之间的通信的?br />
    1. 基础知识Q?/span>
    C API是一l能使C/C++代码与Lua交互的函数。其中包括读写Lua全局变量、调用Lua函数、运行一DLua代码Q以及注册C函数以供Lua代码调用{。这里先l出一个简单的CZ代码Q?/p>
复制代码
 1 #include <stdio.h>
2 #include <string.h>
3 #include <lua.hpp>
4 #include <lauxlib.h>
5 #include <lualib.h>
6
7 int main(void)
8 {
9 const char* buff = "print(\"hello\")";
10 int error;
11 lua_State* L = luaL_newstate();
12 luaL_openlibs(L);
13
14 error = luaL_loadbuffer(L,buff,strlen(buff),"line") || lua_pcall(L,0,0,0);
15 int s = lua_gettop(L);
16 if (error) {
17 fprintf(stderr,"%s",lua_tostring(L,-1));
18 lua_pop(L,1);
19 }
20 lua_close(L);
21 return 0;
22 }
复制代码

    下面是针对以上代码给出的具体解释Q?br />    1). 上面的代码是Z我的C++工程Q而非C工程Q因此包含的头文件是lua.hppQ如果是C工程Q可以直接包含lua.h?br />    2). Lua库中没有定义M全局变量Q而是所有的状态都保存在动态结构lua_State中,后面所有的C API都需要该指针作ؓW一个参数?br />    3). luaL_openlibs函数是用于打开Lua中的所有标准库Q如io库、string库等?br />    4). luaL_loadbuffer~译了buff中的Lua代码Q如果没有错误,则返?Q同时将~译后的E序块压入虚拟栈中?br />    5). lua_pcall函数会将E序块从栈中弹出Qƈ在保护模式下q行该程序块。执行成功返?Q否则将错误信息压入栈中?br />    6). lua_tostring函数中的-1Q表C栈的索引|栈底的烦引gؓ1Q以此类推。该函数返回栈的错误信息Q但是不会将其从栈中弹出?br />    7). lua_pop是一个宏Q用于从虚拟栈中弹出指定数量的元素,q里?表示仅弹出栈的元素?br />    8). lua_close用于释放状态指针所引用的资源?br />
    2. 栈:
    在Lua和C语言之间q行数据交换Ӟ׃两种语言之间有着较大的差异,比如Lua是动态类型,C语言是静态类型,Lua是自动内存管理,而C语言则是手动内存理。ؓ了解册些问题,Lua的设计者用了虚拟栈作Z者之间数据交互的介质。在C/C++E序中,如果要获取Lua的|只需调用Lua的C API函数QLua׃指定的值压入栈中。要一个glLuaӞ需要先该值压入栈Q然后调用Lua的C APIQLua׃获取该值ƈ其从栈中弹出。ؓ了可以将不同cd的值压入栈Q以及从栈中取出不同cd的|Lua为每U类型均讑֮了一个特定函数?br />    1). 压入元素Q?br />    Lua针对每种CcdQ都有一个C API函数与之对应Q如Q?br />    void lua_pushnil(lua_State* L);  --nil?/span>
    void lua_pushboolean(lua_State* L, int b); --布尔?/span>
    void lua_pushnumber(lua_State* L, lua_Number n); --点?/span>
    void lua_pushinteger(lua_State* L, lua_Integer n);  --整型
    void lua_pushlstring(lua_State* L, const char* s, size_t len); --指定长度的内存数?/span>
    void lua_pushstring(lua_State* L, const char* s);  --以零l尾的字W串Q其长度可由strlen得出?/span>
    对于字符串数据,Lua不会持有他们的指针,而是调用在API时生成一个内部副本,因此Q即使在q些函数q回后立刻释放或修改q些字符串指针,也不会有M问题?br />    在向栈中压入数据Ӟ可以通过调用下面的函数判断是否有_的栈I间可用Q一般而言QLua会预?0个槽位,对于普通应用来说已l够了Q除非是遇到有很多参数的函数?br />    int lua_checkstack(lua_State* L, int extra) --期望得到extra数量的空闲槽位,如果不能扩展q获得,q回false?/span> 
    
    2). 查询元素Q?br />    API使用“索引”来引用栈中的元素Q第一个压入栈的ؓ1Q第二个?Q依此类推。我们也可以使用负数作ؓ索引|其中-1表示为栈元素,-2为栈下面的元素Q同样依此类推?br />    Lua提供了一l特定的函数用于查返回元素的cdQ如Q?br />    int lua_isboolean (lua_State *L, int index);
    int lua_iscfunction (lua_State *L, int index);
    int lua_isfunction (lua_State *L, int index);
    int lua_isnil (lua_State *L, int index);
    int lua_islightuserdata (lua_State *L, int index);
    int lua_isnumber (lua_State *L, int index);
    int lua_isstring (lua_State *L, int index);
    int lua_istable (lua_State *L, int index);
    int lua_isuserdata (lua_State *L, int index);
    以上函数Q成功返?Q否则返?。需要特别指出的是,对于lua_isnumber而言Q不会检查值是否ؓ数字cdQ而是查值是否能转换为数字类型?br />    Luaq提供了一个函数lua_typeQ用于获取元素的cdQ函数原型如下:
    int lua_type (lua_State *L, int index);
    该函数的q回gؓ一l常量|分别是:LUA_TNIL、LUA_TNUMBER、LUA_TBOOLEAN、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA、LUA_TTHREAD和LUA_TLIGHTUSERDATA。这些常量通常用于switch语句中?br />    除了上述函数之外QLuaq提供了一l{换函敎ͼ如:
    int lua_toboolean (lua_State *L, int index);
    lua_CFunction lua_tocfunction (lua_State *L, int index);
    lua_Integer lua_tointeger (lua_State *L, int index);    
    const char *lua_tolstring (lua_State *L, int index, size_t *len);
    lua_Number lua_tonumber (lua_State *L, int index);
    const void *lua_topointer (lua_State *L, int index);
    const char *lua_tostring (lua_State *L, int index);
    void *lua_touserdata (lua_State *L, int index);
    --stringcdq回字符串长度,tablecdq回操作W?#'{同的结果,userdatacdq回分配的内存块长度?/span>
    size_t lua_objlen (lua_State *L, int index); 
    对于上述函数Q如果调用失败,lua_toboolean、lua_tonumber、lua_tointeger和lua_objlen均返?Q而其他函数则q回NULL。在很多时?不是一个很有效的用于判断错误的|但是ANSI C没有提供其他可以表示错误的倹{因此对于这些函敎ͼ在有些情况下需要先使用lua_is*pd函数判断是否cd正确Q而对于剩下的函数Q则可以直接通过判断q回值是否ؓNULL卛_?br />    对于lua_tolstring函数q回的指向内部字W串的指针,在该索引指向的元素被弹出之后Q将无法保证仍然有效。该函数q回的字W串末尾均会有一个尾??br />    下面给Z个工具函敎ͼ可用于演CZ面提到的部分函数Q如Q?/p>

复制代码
 1 static void stackDump(lua_State* L) 
2 {
3 int top = lua_gettop(L);
4 for (int i = 1; i <= top; ++i) {
5 int t = lua_type(L,i);
6 switch(t) {
7 case LUA_TSTRING:
8 printf("'%s'",lua_tostring(L,i));
9 break;
10 case LUA_TBOOLEAN:
11 printf(lua_toboolean(L,i) ? "true" : "false");
12 break;
13 case LUA_TNUMBER:
14 printf("%g",lua_tonumber(L,i));
15 break;
16 default:
17 printf("%s",lua_typename(L,t));
18 break;
19 }
20 printf("");
21 }
22 printf("\n");
23 }
复制代码

    3). 其它栈操作函敎ͼ
    除了上面l出的数据交换函C外,Lua的C APIq提供了一l用于操作虚拟栈的普通函敎ͼ如:
    int lua_gettop(lua_State* L); --q回栈中元素的个数?/span>
    void lua_settop(lua_State* L, int index); --栈设|ؓ指定的烦引倹{?/span>
    void lua_pushvalue(lua_State* L, int index); --指定烦引的元素副本压入栈?/span>
    void lua_remove(lua_State* L, int index); --删除指定索引上的元素Q其上面的元素自动下UR?/span>
    void lua_insert(lua_State* L, int index); --栈元素插入到该烦引值指向的位置?/span>
    void lua_replace(lua_State* L, int index); --弹出栈顶元素Qƈ该D|到指定索引上?/span>
    Luaq提供了一个宏用于弹出指定数量的元素:#define lua_pop(L,n)  lua_settop(L, -(n) - 1)    
    见如下示例代码:

复制代码
 1 int main()
2 {
3 lua_State* L = luaL_newstate();
4 lua_pushboolean(L,1);
5 lua_pushnumber(L,10);
6 lua_pushnil(L);
7 lua_pushstring(L,"hello");
8 stackDump(L); //true 10 nil 'hello'
9
10 lua_pushvalue(L,-4);
11 stackDump(L); //true 10 nil 'hello' true
12
13 lua_replace(L,3);
14 stackDump(L); //true 10 true 'hello'
15
16 lua_settop(L,6);
17 stackDump(L); //true 10 true 'hello' nil nil
18
19 lua_remove(L,-3);
20 stackDump(L); //true 10 true nil nil
21
22 lua_settop(L,-5);
23 stackDump(L); //true
24
25 lua_close(L);
26 return 0;
27 }
复制代码


    3. C API中的错误处理Q?/span>
    1). CE序调用Lua代码的错误处理:
    通常情况下,应用E序代码是以“无保?#8221;模式q行的。因此,当Lua发现“内存不”q类错误Ӟ只能通过调用“紧?#8221;函数来通知C语言E序Q之后在l束应用E序。用户可通过lua_atpanic来设|自q“紧?#8221;函数。如果希望应用程序代码在发生Lua错误时不会退出,可通过调用lua_pcall函数以保护模式运行Lua代码。这样再发生内存错误Ӟlua_pcall会返回一个错误代码,q将解释器重|ؓ一致的状态。如果要保护与Lua的C代码Q可以?span style="color: #0000ff;">lua_cpall
函数Q它接受一个C函数作ؓ参数Q然后调用这个C函数?br />    
    2). Lua调用CE序Q?br />    通常而言Q当一个被Lua调用的C函数到错误Ӟ它就应该调用lua_errorQ该函数会清理Lua中所有需要清理的资源Q然后蟩转回发v执行的那个lua_pcallQƈ附上一条错误信息?/p>

沛沛 2014-02-17 17:44 发表评论
]]>
Step By Step(Luapȝ?http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205804.html沛沛沛沛Mon, 17 Feb 2014 09:43:00 GMThttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205804.htmlhttp://m.shnenglu.com/mmdengwo/comments/205804.htmlhttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205804.html#Feedback0http://m.shnenglu.com/mmdengwo/comments/commentRss/205804.htmlhttp://m.shnenglu.com/mmdengwo/services/trackbacks/205804.html  LuaZ保证高度的可UL性,因此Q它的标准库仅仅提供了非常少的功能,特别是和OS相关的库。但是Luaq提供了一些扩展库Q比如Posix库等。对于文件操作而言Q该库仅提供?span style="color: #0000ff;">os.rename函数?span style="color: #0000ff;">os.remove函数?br />    
    1. 日期和时_
    在Lua中,函数time?span style="color: #0000ff;">date提供了所有的日期和时间功能?br />    如果不带M参数调用time函数Q它以数字形式q回当前的日期和旉。如果以一个table作ؓ参数Q它返回一个数字,表示该table中所描述的日期和旉。该table的有效字D如下:

字段?/span>描述
year一个完整的q䆾
month01-12
day01-31
hour00-23
min00-59
sec00-59
isdst布尔|true表示夏o?/span>

    print(os.time{year = 1970, month = 1, day = 1, hour = 8, min = 0}) --北京是东八区Q所以hour{于时表CUTC??/span>
    print(os.time())  --输出当前旉距离1970-1-1 00:00:00所l过的秒数。输出gؓ 1333594721
    函数date是time的反函数Q即可以timeq回的数字D{换ؓ更高U的可读格式Q其W一个参数是格式化字W串Q表C期望的日期q回格式Q第二个参数是日期和旉的数字,~省为当前日期和旉。如Q?/p>

复制代码
 1 dd = os.date("*t",os.time())  --如果格式化字W串?*t"Q函数将q回table形式的日期对象?/span>如果?!*t"Q则表示为UTC旉格式?br /> 2 print("year = " .. dd.year)
3 print("month = " .. dd.month)
4 print("day = " .. dd.day)
5 print("weekday = " .. dd.wday) --一个星期中的第几天Q周日是W一?/span>
6 print("yearday = " .. dd.yday) --一q中的第几天Q??日是W一?/span>
7 print("hour = " .. dd.hour)
8 print("min = " .. dd.min)
9 print("sec = " .. dd.sec)
10
11 --[[
12 year = 2012
13 month = 4
14 day = 5
15 weekday = 5
16 yearday = 96
17 hour = 11
18 min = 13
19 sec = 44
20 --]]
复制代码

    date函数的格式化标识和Cq行时库中的strftime函数的标识完全相同,见下表:

关键?/span>描述
%a一星期中天数的~写Q如Wed
%A一星期中天数的全称Q如Friday
%b月䆾的羃写,如Sep
%B月䆾的全Uͼ如September
%c日期和时?/span>
%d一个月中的W几?01-31)
%H24时制中的小时数(00-23)
%I12时制中的小时数(01-12)
%j一q中的第几天(001-366)
%M分钟(00-59)
%m月䆾(01-12)
%p"上午(am)"?下午(pm)"
%SU数(00-59)
%w一星期中的W几?0--6{h于星期日--星期?
%x日期Q如09/16/2010
%X旉Q如23:48:20
%y两位数的q䆾(00-99)
%Y完整的年?2012)
%%字符'%'

    print(os.date("%Y-%m-%d"))  --输出2012-04-05
    函数os.clock()q回CPU旉的描qͼ通常用于计算一D代码的执行效率。如Q?/p>

复制代码
1 local x = os.clock()
2 local s = 0
3 for i = 1, 10000000 do
4 s = s + i
5 end
6 print(string.format("elapsed time: %.2f\n", os.clock() - x))
7
8 --输出l果为:
9 --elapsed time: 0.21
复制代码


    2. 其他pȝ调用Q?/span>
    函数os.exit()可中止当前程序的执行。函?span style="color: #0000ff;">os.getenv()
可获取一个环境变量的倹{如Q?br />    print(os.getenv("PATH"))  --如果环境变量不存在,q回nil?/span>
    os.execute函数用于执行和操作系l相关的命oQ如Q?br />    os.execute("mkdir " .. "hello")



沛沛 2014-02-17 17:43 发表评论
]]>
Step By Step(Lua输入输出?http://m.shnenglu.com/mmdengwo/archive/2014/02/17/205803.html沛沛沛沛Mon, 17 Feb 2014 09:43:00 GMThttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205803.htmlhttp://m.shnenglu.com/mmdengwo/comments/205803.htmlhttp://m.shnenglu.com/mmdengwo/archive/2014/02/17/205803.html#Feedback0http://m.shnenglu.com/mmdengwo/comments/commentRss/205803.htmlhttp://m.shnenglu.com/mmdengwo/services/trackbacks/205803.html  I/O库ؓ文g操作提供了两U不同的模型Q简单模型和完整模型。简单模型假设一个当前输入文件和一个当前输出文Ӟ他的I/O操作均作用于q些文g。完整模型则使用昑ּ的文件句柄,q将所有的操作定义为文件句柄上的方法?br />    1. 单模型:
    I/O库会进E标准输入输Z为其~省的输入文件和输出文g。我们可以通过io.input(filename)?span style="color: #0000ff;">io.output(filename)q两个函数来改变当前的输入输出文件?br />    1). io.write函数Q?br />    函数原型为io.write(...)。该函数所有参数顺序的写入到当前输出文件中。如Q?br />    io.write("hello","world") --写出的内容ؓhelloworld

    2). io.read函数Q?br />    下表l出了该函数参数的定义和功能描述Q?/p>
参数字符?/span>含义
"*all"d整个文g
"*line"d下一?/span>
"*number"d一个数?/span>
<num>d一个不过<num>个字W的字符?/span>

    调用io.read("*all")会读取当前输入文件的所有内容,以当前位|作为开始。如果当前位|处于文件的末尾Q或者文件ؓI,那个该调用返回一个空字符丌Ӏ由于Lua可以高效的处理长字符Ԍ因此在Lua中可以先数据从文g中完整读出,之后在通过Lua字符串库提供的函数进行各U处理?br />    调用io.read("*line")会返回当前文件的下一行,但不包含换行W。当到达文g末尾Ӟ该调用返回nil。如Q?/p>

复制代码
1 for count = 1,math.huge do
2 local line = io.read("*line") --如果不传参数Q缺省g?*line"
3 if line == nil then
4 break
5 end
6 io.write(string.format("%6d ",count),line,"\n")
7 end
复制代码

    如果只是Zq代文g中的所有行Q可以?span style="color: #0000ff;">io.lines函数Q以q代器的形式讉K文g中的每一行数据,如:

复制代码
1 local lines = {}
2 for line in io.lines() do --通过q代器访问每一个数?/span>
3 lines[#lines + 1] = line
4 end
5 table.sort(lines) --排序QLua标准库的table库提供的函数?/span>
6 for _,l in ipairs(lines) do
7 io.write(l,"\n")
8 end
复制代码

    调用io.read("*number")会从当前输入文g中读取一个数字。此时read直接返回一个数字,而不是字W串?*number"选项会忽略数字前面所有的I格Qƈ且能处理?3?5.2q样的数字格式。如果当前读取的数据不是合法的数字,readq回nil。在调用read是可以指定多个选项Q函CҎ每个选项参数q回相应的内宏V如Q?/p>

复制代码
 1 --[[
2 6.0 -3.23 1000
3 ... ...
4 下面的代码读取注释中的数?br /> 5 --]]
6 while true do
7 local n1,n2,n3 = io.read("*number","*number","*number")
8 if not n1 then
9 break
10 end
11 print(math.max(n1,n2,n3))
12 end
复制代码

    调用io.read(<num>)会从输入文g中最多读取n个字W,如果MCQ何字W,q回nil。否则返回读取到的字W串。如Q?/p>

复制代码
1 while true do
2 local block = io.read(2^13)
3 if not block then
4 break
5 end
6 io.write(block)
7 end
复制代码

    io.read(0)是一U特D的情况Q用于检查是否到达了文g的末。如果没有到达,q回I字W串Q否则nil?br />
    2. 完整I/O模型Q?/span>
    Lua中完整I/O模型的用方式非常类gCq行时库的文件操作函敎ͼ它们都是Z文g句柄的?br />    1). 通过io.open函数打开指定的文Ӟq且在参Cl出对该文g的打开模式Q其?span style="color: #0000ff;">"r"
表示dQ?span style="color: #0000ff;">"w"表示覆盖写入Q即先删除文件原有的内容Q?span style="color: #0000ff;">"a"表示q加式写入,"b"表示以二q制的方式打开文g。在成功打开文g后,该函数将q回表示该文件的句柄Q后面所有基于该文g的操作,都需要将该句柄作为参C入。如果打开p|Q返回nil。其中错误信息由该函数的W二个参数返回,如:
    assert(io.open(filename,mode))  --如果打开p|Qassert打印第二个参数l出的错误信息?/span>
    
    2). 文gd函数read/write。这里需要用到冒可法,如:

1 local f = assert(io.open(filename,"r"))
2 local t = f:read("*all") --对于read而言Q其参数完全{同于简单模型下read的参数?/span>
3 f:close()

    此外QI/O库还提供?个预定义的文件句柄,?span style="color: #0000ff;">io.stdin(标准输入)、io.stdout(标准输出)、io.stderr(标准错误输出)。如Q?br />    io.stderr:write("This is an error message.")
    事实上,我们也可以؜合用简单模式和完整模式Q如Q?/p>

1 local temp = io.input()   --当前文件句柄保?/span>
2 io.input("newInputfile") --打开新的输入文g
3 io.input():close() --关闭当前文g
4 io.input(temp) --恢复原来的输入文?/span>


    3). 性能技巧:
    ׃一ơ性读取整个文件比逐行d要快一些,但对于较大的文gQ这样ƈ不可行,因此Lua提供了一U折中的方式Q即一ơ读取指定字节数量的数据Q如果当前读取中的最后一行不是完整的一行,可通过该方式将该行的剩余部分也一q读入,从而保证本ơ读取的数据均ؓ整行数据Q以便于上层逻辑的处理。如Q?br />    local lines,rest = f:read(BUFSIZE,"*line") --rest变量包含最后一行中没有d的部分?/span>
    下面是Shell中wc命o的一个简单实现?/p>

复制代码
 1 local BUFSIZE = 8192
2 local f = io.input(arg[1]) --打开输入文g
3 local cc, lc, wc, = 0, 0, 0 --分别计数字符、行和单?
4 while true do
5 local lines,rest = f:read(BUFSIZE,"*line")
6 if not lines then
7 break
8 end
9 if rest then
10 lines = lines .. rest .. "\n"
11 end
12 cc = cc + #lines
13 --计算单词数量
14 local _, t = string.gsub(lines."%S+","")
15 wc = wc + t
16 --计算行数
17 _,t = string.gsub(line,"\n","\n")
18 lc = lc + t
19 end
20 print(lc,wc,cc)
复制代码


    4). 其它文g操作Q?br />    ?span style="color: #0000ff;">io.flush函数会将io~存中的数据h到磁盘文件上?span style="color: #0000ff;">io.close函数关闭当前打开的文件?span style="color: #0000ff;">io.seek函数用于讄或获取当前文件的d位置Q其函数原型?span style="color: #0000ff;">f:seek(whence,offset)Q如果whence的gؓ"set"Qoffset的值则表示为相对于文g起始位置的偏U量。如?span style="color: #0000ff;">"cur"(默认?,offset则ؓ相对于当前位|的偏移量,如ؓ"end"Q则为相对于文g末尾的偏U量。函数的q回gwhence参数无关QLq回文g的当前位|,即相对于文g起始处的偏移字节数。offset的默认gؓ0。如Q?/p>

1 function fsize(file)
2 local current = file:seek() --获取当前位置
3 local size = file:seek("end") --获取文g大小
4 file:seek("set",current) --恢复原有的当前位|?/span>
5 return size
6 end

    最后需要指出的是,如果发生错误Q所有这些函数均q回nil和一条错误信息?/p>

沛沛 2014-02-17 17:43 发表评论
]]>
Ʒþ| þþøƵ| Ʒþþþ9999| ƷƷھþø| AëƬþþƷ| ŷһþþþþþôƬ| þþƷɫ鶹| þþƷˬӰ| þþƷĻ| wwþþþþþþþ| þAVһ| þùƷHDAV| պʮ˽һþ| þˬˬƬAV| þþ뾫Ʒҹ| þĻƷѩ| ˾þþƷ鶹һ| þþƷAVɫ| þù鶹91| ľƷþþþ޲| 99þþƷһëƬ| ޺ݺۺϾþѿ| þþžѸƵ| þþùƷվ| ھƷþþþӰԺ| ۺϾþþƷ| þþƷһӰԺ| ھƷþþþþþþ| ƷѸþ| ޾ƷĻþò| þƵ1| ˾þô߽ۺ5g| ھƷþþþþþ| þþþƷ| ۺϾþþ| þ99Ʒþþþþˮ| þùƷ| ó˾þAvѸ| þþƷҹƬ| ҹƷþþþþ| ޾þþһ |