当前位置: 首页 > news >正文

Lua 程序设计 (Roberto,Ierusalimschy 著)

1 开始

2 类型与值

3 表达式

4 语句

5 函数

6 深入函数

7 迭代器与泛型for

8 编译,执行与错误

9 协同程序(coroutine)

10 完整的示例

11 数据结构

12 数据文件与持久性

13 元表(metatable)与元方法(metamethod)

14 环境

15 模块与包

16 面向对象编程

17 弱引用

18 数学库

19 table库

20 字符串表

21 I/O库

22 操作系统库

23 调试库

24 C API概述

25 扩展应用程序

26 从Lua调用C

27 编写C函数的技术

28 用户自定义类型

29 管理资源

30 线程和状态

31 内存管理

 

1 开始

Hello World

print("Hello World");

程序块(chunk)

一个程序块也就是一连串的语句或命令

几条连续的Lua语句之间并不需要分隔符,但如果愿意,也可以使用分号来分隔语句.

Lua通常还被作为一种数据描述语言来使用,几兆字节的程序块也是很常见的.

交互模式:

退出交互模式:UNIX(Ctrl+D),Windows(Ctrl+Z). os.exit()

运行完指定程序后进入交互模式:%lua -i prog 

交互模式中使用dofile函数立即执行一个文件:

词法规范

Lua中的标识符可以是由任意字母,数字和下划线构成的字符串,但不能以数字开头

应该避免使用以一个下划线开头并跟着一个或多个大写字母的标识符,Lua将这类标识符保留用作特殊用途

Lua是有大小写之分的

行注释(--),块注释(--[[ ]])

全局变量

全局变量不需要声明

在Lua中,访问一个未初始化的变量不会引发错误,访问结果是一个特殊的值nil

解释器程序(the dtand-slone interpreter)

解释器是一个小型的程序,可以通过它来直接使用Lua

解释器程序的用法:lua [选项参数] [脚本[参数]]

选项参数"-e"可以直接在命令行中输入代码:

选项参数"-l"用于加载库文件.

在脚本代码中,可以通过全局变量arg来检索脚本的启动参数:%lua 脚本 a b c

2 类型与值

Lua是一种动态类型的语言.在语言中没有类型定义的语法.每个值都"携带"了它自身的类型信息

在Lua中,函数是作为"第一类值(first-class value)"来看待的,可以像操作其他值一样来操作一个函数值

nil(空)

nil是一种类型,它只有一个值nil,它的主要功能是用于区别其他任何值.

boolean(布尔)

boolean类型有两个可选值:false和true,这与传统的布尔值一样.然而boolean却不是一个条件值的唯一表示方式.在Lua中任何值都可以表示一个条件.Lua将值false和nil视为"假",而将除此之外的其他值视为"真".Lua在条件测试中, 将数字零和空字符串也都视为"真"

number(数字)

number类型用于表示实数.Lua没有整数类型.

string(字符串)

Lua完全采用8位编码,Lua字符串中的字符可以具有任何数值编码,包括数值0.也就是说,可以将任意二进制数据存储到一个字符串中

Lua的字符串是不可变的值(immutable values)

Lua的字符串和其他Lua对象(例如table或函数等)一样,都是自动内存管理机制所管理的对象

Lua提供了运行时的数字与字符串的自动转换

在Lua中,".."是字符串连接操作符.当直接在一个数字后面输入它的时候,必须要用一个空格来分隔它们.不然,Lua会将第一个点理解为一个小数点.

若要将一个数字转换成字符串,可以调用函数tostring,或者将数该数字与第一个空字符串相连接

在Lua5.1中,可以在字符串前放置操作符"#"来获得该字符串的长度

table(表)

在Lua中,table既不是"值"也不是"变量",而是"对象".可以将一个table想象成一种动态分配的对象,程序仅持有一个对它们的引用(或指针),Lua不会暗中产生table的副本或创建新的table.此外,在Lua中也不需要声明一个table.事实上也没有办法可以声明table.table的创建是通过"构造表达式(constructor expression)"完成的,最简单的构造表达式是{}.

table永远是"匿名的(anonymous)",一个持有table的变量与table自身之间没有固定的关联性.

当一个程序再也没有对一个table的引用时,Lua的垃圾收集器(garbage collector)最终会删除该table,并复用它的内存

 

function(函数)

在Lua中,函数是作为"第一类值"来看待的.这表示函数可以存储在变量中,可以通过参数传递给其他函数,还可以作为其他函数的返回值.

userdata(自定义类型)和thread(线程)

由于userdata类型可以将任意的C语言数据存储到Lua变量中.在Lua中,这种类型没有太多的预定义操作,只能进行赋值和相等性测试.

3 表达式

算术操作符

Lua支持常规的算术操作符有: + - * / ^ % -(负号)

关系操作符

Lua提供了以下关系操作符: < > <= >= == ~= 所有这些操作符的运算结果都是true或false 特别需要说明的是,nil只与其自身相等

对于table,userdata和函数,Lua是作引用比较的.也就是说,只有当它们引用同一个对象时,才认为它们相等.

只能对两个数字或两个字符串作大小性比较.而数字和字符串之外的其他类型只能进行相等性或不等性比较.

当对两个不同类型的值作比较时,要格外小心.请记住,"0"与0是不同的

逻辑操作符

逻辑操作符有and,or和not.与条件控制语句一样,所有的操作符将false和nil视为假,而将其他的任何东西视为真.

and和or都是使用"短路求值(short-cut evaluation)"

有一种常用的Lua习惯写法"x=x or v",它等价于 if not x then x = v end

字符串连接

要在Lua中连接两个字符串,可以使用操作符"..".如果其任意一个操作数是数字的话,Lua会将这个数字转换成一个字符串

请记住,Lua中的字符串是不可变的值(immutable value).连接操作符只会创建一个新字符串,而不会对其原操作数进行任何修改.

优先级

在二元操作符中,除了指数操作符"^"和连接操作符".."是"右结合"的,所有其他操作符都是"左结合(left associative)"的.

table构造式(table constructor)

最简单的构造式就是一个空构造式{},用于创建一个空table

列表风格:

记录风格:

记录风格与列表风格的混合:

通用格式: 

无论是列表风格的初始化,还是记录风格的初始化,起始都是这种通用语法特例.{x=0,y=0}等价于{["x"]=0,["y"]=0},{“r","g","b"}等价于{[1]="r",[2]="g",[3]="b"}

不推荐在Lua中以0作为数组的起始索引

4 语句

赋值

赋值的基本含义(assignment)的基本含义是修改一个变量或一个table中字段的值

Lua允许"多重赋值"

在多重赋值中,Lua先对等号右边的所有元素求值,然后才执行赋值.这样可以用一句多重赋值来交换两个变量

Lua总是会将等号右边值的个数调整到与左边变量的个数相一致.

多重赋值的常见用法,交换两个变量,收集函数的多个返回值

局部变量和块(block)

Lua通过local语句来创建局部变量

与全局变量不同的是,局部变量的作用域仅限于声明它们的那个块.一个块(block)是一个控制结构的执行体,或者是一个函数的执行体再或者是一个程序块(chunk)

交互模式中每行输入内容自身就形成了一个程序块.使用do-end显示界定一个块

控制结构

用于条件执行的if,用于迭代的while,repeat和for.所有的控制结果都有一个显示的终止符:if,for和while以end作为结尾,repeat以until作为结尾

Lua不支持switch

在Lua中一个声明在循环体中的局部变量的作用域包括了条件测试

for语句有两种形式:数字型for(numeric for)和泛型for(generic for).

数字型for循环和泛型for循环有两个相同点:  1.循环变量是循环体的局部变量.  2.绝不应该对循环变量作任何赋值

数字型for的语法如下:

  for var=exp1,exp2,exp3 do

    <执行体>

  end

var 从exp1变化到exp2,每次变化都以exp3作为步长(step)递增var,并执行一次"执行体".第三个表达式exp3是可选的,若不指定的话,Lua会将步长默认为1

泛型for循环通过一个迭代器(iterator)函数来遍历所有值

标准库提供了几种迭代器,包括用于迭代文件中每行的(io.line),迭代table元素的(pairs),迭代数组元素的(ipairs),迭代字符串中单词的(string.gmatch)

break与return

break和return语句用于跳出当前的块

5 函数

Lua为面向对象式的调用也提供了一种特殊的语法---冒号操作符.表达式o.foo(o,x)的另一种写法是o:foo(x),冒号操作符使调用o.foo时将o隐含地作为函数的第一个参数.

多重返回值(multiple results)

关于多重返回值还要介绍一个特殊函数--unpack.它接受一个数组作为参数,并从下标1开始返回该数组的所有元素:

unpack的一项重要用途体现在"泛型调用(generic call)"机制中.泛型调用机制可以动态地以任何实参来调用

变长参数(variable number of arguments)

具名实参(named arguments)

6 深入函数

closure(闭合函数)

非全局的函数(non-global function)

正确的尾调用(propertailcall)

7 迭代器与泛型for

迭代器与closure

泛型for的语义

无状态的迭代器

 1 a = {"one","two","three"}
 2 for i,v in ipairs(a) do
 3     print(i,v)
 4 end
 5 
 6 local function iter(a,i)
 7     i = i + 1
 8     local v = a[i]
 9     if v then
10         return i,v
11     end
12 end
13 
14 function ipairs(a)
15     return iter,a,0
16 end
17 
18 function pairs(t)
19     return next,t,nil
20 end
21 
22 for k,v in next,t do
23     <loop body>
24 end
25 
26 local function getnext(list,node)
27     if not node then
28         return list
29     else
30         return node.next
31     end
32 end
33 
34 function traverse(list)
35     return getnext,list,nil
36 end
37 
38 list = nil
39 for line in io.lines() do
40     list = {val = line,next = list}
41 end
42 
43 for node in traverse(list) do
44     print(node.val)
45 end
View Code

具有复杂状态的迭代器

真正的迭代器

8 编译,执行与错误

编译

C代码

错误(error)

错误处理与异常

错误消息与追溯(traceback)

9 协同程序(coroutine)

协同程序基础

 1 co = coroutine.create(function() print("hi") end)
 2 print(co)    --thread:00B5C840
 3 
 4 print(coroutine.status(co))    --suspended
 5 
 6 coroutine.resume(co)    --hi
 7 
 8 print(coroutine.status(co))    --dead
 9 
10 co = coroutine.create(function ()
11     for i = 1,3 do
12         print("co",i)
13         coroutine.yield()
14     end
15 end)
16 
17 coroutine.resume(co)     --co    1
18 print(coroutine.status(co))    --suspended
19 
20 coroutine.resume(co)    --co    2
21 coroutine.resume(co)    --co    3
22 coroutine.resume(co)    --什么都不打印
23 
24 print(coroutine.resume(co))    --false cannot resume dead coroutine
25 
26 co = coroutine.create(function(a,b,c)
27     print("co",a,b,c)
28     end)
29 coroutine.resume(co,1,2,3)    --co 1 2 3
30 
31 co = coroutine.create(function(a,b)
32     coroutine.yield(a+b,a-b)
33     end)
34 print(coroutine.resume(co,20,10))    --true 30 10
35 
36 co = coroutine.create(function()
37     print("co",coroutine.yield())
38     end)
39 coroutine.resume(co)
40 coroutine.resume(co,4,5)    --co 4 5
41 
42 co = coroutine.create(function()
43     return 6,7
44     end)
45 print(coroutine.resume(co))    --true 6 7
View Code

管道(pipe)与过滤器(filter)

 1 function producer()
 2     while true do
 3         local x = io.read()        --产生新的值?
 4         send(x)    --发送给消费者
 5     end
 6 end
 7 
 8 function consumer()
 9     while true do
10         local x = receive()    --从生产者接收值
11         io.write(x,"\n")    --消费新的值
12     end
13 end
14 
15 function receive()
16     local status,value = coroutine.resume(producer)
17     return value
18 end
19 
20 function send(x)
21     coroutine.yield(x)
22 end
23 
24 producer = coroutine.create(
25     function()
26         while true do
27             local x = io.read()    --产生新值
28             send(x)
29         end
30     end)
31 
32 function receive(prod)
33     local status,value = coroutine.resume(prod)
34     return value
35 end
36 
37 function send(x)
38     coroutine.yield(x)
39 end
40 
41 function producer()
42     return coroutine.create(function()
43         while true do
44             local x = io.read()    --产生新值
45             send(x)
46         end
47     end)
48 end
49 
50 function filter(prod)
51     return coroutine.create(function()
52         for line = 1,math.huge do
53             local x = receive(prod)    --获取新值
54             x = string.format("%5d%s",line,x)
55             send(x)    --将新值发送给消费者
56         end
57     end)
58 end
59 
60 function consumer(prod)
61     while true do
62         local x = receive(prod)    --获取新值
63         io.write(x,"\n")    --消费新值
64     end
65 end
66 
67 p = producer()
68 f = filter(p)
69 consumer(f)
View Code

以协同程序实现迭代器

 1 function permgen(a,n)
 2     n = n or #a    --默认n为a的大小
 3     if n<= 1 then    --还需要改变吗
 4         printResult(a)
 5     else
 6         for i = 1,n do
 7             --将第i个元素放到数组末尾
 8             a[n],a[i] = a[i],a[n]
 9             --生成其余元素的排列
10             permgen(a,n-1)
11             --恢复第i个元素
12             a[n],a[i] = a[i],a[n]
13         end
14     end
15 end
16 
17 function printResult(a)
18     for i = 1,#a do
19         io.write(a[i]," ")
20     end
21     io.write("\n")
22 end
23 
24 permgen({1,2,3,4})
25 
26 function permgen(a,n)
27     n = n or #a
28     if n <= 1 then
29         coroutine.yield(a)
30     else
31         <as before>
32         
33 function permutations(a)
34     local co = coroutine.create(function() permgen(a) end)
35     return function()    --迭代器
36         local code,res = coroutine.resume(co)
37         return res
38     end
39 end
40 
41 for p in permutations{"a","b","c"} do
42     printResult(p)
43 end
View Code

非抢先式的(non-preemptive)多线程

10 完整的示例

暂无

11 数据结构

数组

矩阵与多维数组

链表

队列与双向队列

 1 function ListNew()
 2     return {first=0,last=-1}
 3 end
 4 
 5 List = {}
 6 function List.new()
 7     return {first=0,last=-1}
 8 end
 9 
10 function List.pushfirst(list,value)
11     local first = list.first-1
12     list.first = first
13     list[first] = value
14 end
15 
16 function List.pushlast(list,value)
17     local last = list.last + 1
18     list.last = last
19     list[last] = value
20 end
21 
22 function List.popfirst(list)
23     local first = list.first
24     if first > list.last then error("list is empty") end
25     local value = list[first]
26     list[first] = nil    --为了允许垃圾收集
27     list.first = first + 1
28     return value
29 end
30 
31 function List.poplast(list)
32     local last = list.last
33     if list.first > last then error("list is empty") end
34     local value = list[last]
35     list[last] = nil    --为了允许垃圾收集
36     list.last = last - 1
37     return value
38 end
View Code

集合与无序组(bag)

 1 reserved = {
 2     ["while"] = true,
 3     ["end"] = true,
 4     ["function"] = true,
 5     ["local"] = true,
 6 }
 7 
 8 for w in allwords() do
 9     if not reserved[w] then
10         <对'w'作任意处理>    --'w'不是保留字
11     end
12 end
13 
14 function Set(list)
15     local set = {}
16     for _,l in ipairs(list) do set[l] = true end
17     return set
18 end
19 
20 reserved = Set{"while","end","function","local"}
21 
22 function insert(bag,element)
23     bag[element] = (bag[element] or 0) + 1
24 end
25 
26 function remove(bag,element)
27     local count = bag[element]
28     bag[element] = (count and count > 1) and count - 1 or nil
29 end
View Code

字符串缓冲


12 数据文件与持久性

数据文件

 

串行化(Serialization)

 

13 元表(metatable)与元方法(metamethod)

可以通过元表来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作

Lua中的每个值多又一个元表.table和userdata可以有各自独立的元表,而其他类型的值则共享其类型所属的单一元表

Lua在创建新的table时不会创建元表:

可以使用setmetatable来设置或修改任何table的元表:

任何table都可以作为任何值的元表,而一组相关的table也可以共享一个通用的元素,此元表描述了它们共同的行为.一个table甚至可以作为它自己的元表,用于描述其特有的行为.

在Lua代码中,只能设置table的元表.若要设置其他类型的值的元表,则必须通过C代码来完成.

算术类的元方法

在元表中,每种算术操作符多有对应的字段名.__add,__mul,__sub,__div,_unm(相反数),__mod,__pow,__concat

 1 Set = {}
 2 local mt = {}    --集合的元表
 3 
 4 --根据参数列表中的值创建一个新的集合
 5 function Set.new(l)
 6     local set = {}
 7     setmetatable(set,mt)
 8     for _,v in ipairs(l) do
 9         set[v] = true
10     end
11     return set
12 end
13 
14 function Set.union(a,b)
15     local res = Set.new{}
16     for k in pairs(a) do
17         res[k] = true
18     end
19     for k in pairs(b) do
20         res[k] = true
21     end
22     return res
23 end
24 
25 function Set.intersection(a,b)
26     local res = Set.new{}
27     for k in pairs(a) do
28         res[k] = b[k]
29     end
30     return res
31 end
32 
33 function Set.tostring(set)
34     local l = {}    --用于存放集合中所有元素的列表
35     for e in pairs(set) do
36         l[#l + 1] = e
37     end
38     return "{" .. table.concat(l,", ") .. "}"
39 end
40 
41 function Set.print(s)
42     print(Set.tostring(s))
43 end
44 
45 
46 
47 s1 = Set.new{10,20,30,50}
48 s2 = Set.new{30,1}
49 
50 print(getmetatable(s1))
51 print(getmetatable(s2))
52 
53 mt.__add = Set.union
54 
55 s3 = s1 + s2
56 Set.print(s3)
57 
58 mt.__mul = Set.intersection
59 Set.print((s1 + s2)*s1)
View Code

关系类的元方法

元表还可以指定关系操作符的含义,元方法为__eq,__lt(小于),__le(小于等于).而其他3个关系操作符则没有单独的元方法,Lua会将a~=b转化为not(a==b),将a>b转化为b<a,将a>=b转化为b<=a

库定义的元方法

table访问的元方法

__index元方法

__newindex元方法

__newindex元方法与__index类似,不同之处在于前者用于table的更新,而后者用于table的查询

具有默认值的table

跟踪table的访问

只读的table

14 环境

Lua将其所有的全局变量保存在一个常规的table中,这个table称为"环境(enviroment)".Lua将环境table自身保存在一个全局变量_G中.

具有动态名字的全局变量

全局变量声明

简单地检测所有对全局table中不存在key的访问

如何声明一个新的变量,其一是使用rawset,它可以绕过元表

另外一种更简单的方法就是只允许在主程序中对全局变量进行赋值

非全局的环境

Lua5允许每个函数拥有一个自己的环境来查找全局变量

15 模块与包

require函数

如果require为指定模块找到了一个Lua文件,它就通过loadfile来加载该文件.而如果找到的是一个C程序库,就通过loadlib来加载.注意,loadfile和loadlib都只是加载了代码,并没有运行它们.

require采用的路径是一连串的模式(pattern),其中每项都是一种将模块名转换为文件名的方式

require用于搜索Lua文件的路径存放在变量package.path中.当Lua启动后,便以环境变量LUA_PATH的值来初始化这个变量.

具有良好行为的C程序库应该导出一个名为"luaopen_<模块名>"的函数.

编写模块的基本方法

在Lua中创建一个模块最简单的方法是:创建一个table,并将所有需要导出的函数放入其中,最后返回这个table.

 

使用环境

 

module函数

 

子模块与包

 

16 面向对象编程

 

继承

多重继承

 1 --在table'plist'中查找'k'
 2 local function search(k,plist)
 3     for i = 1,#plist do
 4         local v = plist[i][k]    --尝试第i个基类
 5         if v then return v end
 6     end
 7 end
 8 
 9 function createClass(...)
10     local c = {}    --新类
11     local parents = {...}
12 
13     --类在其父类列表中的搜索方法
14     setmetatable(c,{__index = function(t,k)
15         return search(k,parent)
16     end})
17 
18     --将'c'作为其实例的元表
19     c.__index = c
20 
21     --为这个新类定义一个新的构造函数(construction)
22     function c:new(o)
23         o = o or {}
24         setmetatable(o,c)
25         return o
26     end
27 
28     return c    --返回新类
29 end
30 
31 Named = {}
32 function Named:getname()
33     return self.name
34 end
35 
36 function Named:setname(n)
37     self.name = n
38 end
39 
40 NamedAccount = createClass(Account,Named)
41 
42 account = NamedAccount:new{name = "Paul"}
43 print(account:getname())    -->Paul
44 
45 setmetatable(c,{__index = function(t,k)
46     local v = search(k,parents)
47     t[k] = v    --保存下来,以备下次访问
48     return v
49 end})
View Code

私密性

单一方法(single-method)做法 

17 弱引用

备忘录函数

对象属性

 

回顾table的默认值

18 数学库

19 table库

插入和删除

排序

连接

20 字符串表

基础字符串函数

模式匹配(pattern-matching)函数

string.find函数

string.match函数

 

string.gsub函数

string.gmatch函数

模式

捕获(capture)

替换

URL编码

 

tab扩展

技巧

21 I/O库

 sdfsdf

22 操作系统库

日期和时间

 

其他系统调用

23 调试库

自省机制

访问局部变量

访问非局部的变量(non-local varible)

访问其他协同程序

钩子

性能剖析(profile)

24 C API概述

第一个示例

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include "lua.h"
 4 #include "lauxlib.h"
 5 #include "lualib.h"
 6 
 7 int main(void){
 8     char buff[256];
 9     int error;
10     lua_State *L = luaL_newstate();    /* 打开Lua */
11     luaL_openlibs(L);    /* 打开标准库 */
12     
13     while(fgets(buff,sizeof(buff),stdin) != NULL){
14         error = luaL_loadbuffer(L,buff,strlen(buff),"line") || lua_pcall(L,0,0,0);
15         if(error) {
16             fprintf(stderr,"%s",lua_tostring(L,-1));
17             lua_pop(L,1);    /* 从栈中弹出错误消息 */
18         }
19     }
20     
21     lua_close(L);
22     return 0;
23 }

压入元素

查询元素

其他栈操作

CAPI中的错误处理

应用程序代码中的错误处理

库代码中的错误处理

25 扩展应用程序

基础

table操作

 1 --配置文件
 2 width = 200
 3 height = 300
 4 background_red = 0.30
 5 background_green = 0.10
 6 background_blue = 0
 7 
 8 background = {r=0.30,g=0.10,b=0}
 9 
10 BLUE = {r=0,g=0,b=1}
11 <其他颜色定义》
12 
13 background = BLUE
14 
15 lua_getglobal(L,"background");
16 if(!lua_istable(L,-1))
17     error(L,"'background' is not a table");
18 
19 red = getfiled(L,"r");
20 green = getfield(L,"g");
21 blue = getfield(L,"b");
22 
23 #define MAX_COLOR 255
24 
25 /* 假设table位于栈顶 */
26 int getfield(lua_State *L,const char *key){
27     int result;
28     lua_pushstring(L,key);
29     lua_gettable(L,-2);    /* 获取background[key] */
30     if(!lua_isnumber(L,-1))
31         error(L,"invalid component in background color");
32     result = (int)lua_tonumber(L,-1) * MAX_COLOR;
33     lua_pop(L,1);    /* 删除数字 */
34     return result;
35 }
View Code

调用Lua函数

一个通用的调用函数

 1 #include <stdarg.h>
 2 
 3 void call_va(const char *func,const char *sig,...){
 4     va_list vl;
 5     int narg,nres;    /*参数和结果的数量*/
 6     
 7     va_start(vl,sig);
 8     lua_getglobal(L,func);    /*压入函数*/
 9     
10     for(narg = 0;*sig;narg++){    /*遍历所有参数*/
11         /*检查栈中空间*/
12         luaL_checkstack(L,1,"too many arguments");
13         
14         switch(*sig++){
15             case 'd':    /*double参数*/
16                 lua_pushnumber(L,va_arg(vl,double));
17                 break;
18             case 'i':    /*int参数*/
19                 lua_pushinteger(L,va_arg(vl,int));
20                 break;
21             case 's':    /*字符串参数*/
22                 lua_pushstring(L,va_arg(vl,char*));
23                 break;
24             case '>':    /*参数结束*/
25                 goto endargs;
26             default:
27                 error(L,"invalid option(%C)",*(sig - 1));
28         }
29     }
30     
31     nres = strlen(sig);    /*期望的结果数量*/
32     
33     if(lua_pcall(L,narg,nres,0) != 0)    /*完成调用*/
34         error(L,"error calling '%s':%s",func,lua_tostring(L,-1));
35         
36     nres = -nres;    /*第一个结果的栈索引 */
37     while(*sig){    /*遍历所有结果*/
38         switch(*sig++){
39             case 'd':    /*double结果*/
40                 if(!lua_isnumber(L,nres))
41                     error(L,"wrong result type");
42                 *va_arg(vl,double *) = lua_tonumber(L,nres);
43                 break;
44             case 'i':    /*int结果*/
45                 if(!lua_isnumber(L,nres))
46                     error(L,"wrong result type");
47                 *va_arg(vl,int *) = lua_tointeger(L,nres);
48                 break;
49             case 's':    /*string结果*/
50                 if(!lua_isstring(L,nres))
51                     error(L,"wrong result type");
52                 *va_arg(vl,const char **) = lua_tostring(L,nres);
53                 break;
54             default:
55                 error(L,"invalid option(%c)",*(sig - 1));
56         }
57         nres++;
58     }
59     
60     va_end(v1);
61 }
View Code

26 从Lua调用C

C函数

C模块

27 编写C函数的技术

数组操作

字符串操作

 1 lua_pushlstring(L,s+i,j-i+1);
 2 
 3 static int l_split(lua_State *L){
 4     const char *s = luaL_checkstring(L,1);
 5     const char *sep = luaL_checkstring(L,2);
 6     const char *e;
 7     int i = 1;
 8     lua_newtable(L);    /*结果*/
 9     
10     /*遍历所有分隔符*/
11     while((e=strchr(s,*sep)) != NULL){
12         lua_pushlstring(L,s,e-s);    /*压入子串*/
13         lua_rawseti(L,-2,i++);
14         s = e + 1;    /*跳过分隔符*/
15     }
16     
17     /*压入最后一个子串*/
18     lua_pushstring(L,s);
19     lua_rawseti(L,-2,i);
20     
21     return 1;    /*返回table*/
22 }
23 
24 const char *lua_pushfstring(lua_State *L,const char *fmt,...);
25 
26 static int str_upper(lua_State *L){
27     size_t l;
28     size_t i;
29     luaL_Buffer b;
30     const char *s = luaL_checklstr(L,1,&l);
31     luaL_bufferinit(L,&b);
32     for(i=0;i<l;i++){
33         luaL_addchar(&b,toupper((unsinged char)(s[i])));
34     }
35     luaL_pushresult(&b);
36     return 1;
37 }
38 
39 void luaL_buffinit(lua_State *L,luaL_Buffer *B);
40 void luaL_addchar(luaL_Buffer *B,char c);
41 void luaL_addlstring(luaL_Buffer *B,const char *s,size_t l);
42 void luaL_addstring(luaL_Buffer *B,const char *s);
43 void lua_pushresult(luaL_Buffer *B);
44 
45 void luaL_addvalue(luaL_Buffer *B);
View Code

在C函数中保存状态

注册表(registry)

C函数的环境

upvalue

28 用户自定义类型

暂无

29 管理资源

暂无

30 线程和状态

多个线程

Lua状态

31 内存管理

分配函数

垃圾收集器

原子操作

垃圾收集器的API

转载于:https://www.cnblogs.com/revoid/p/6611616.html

相关文章:

  • c3p0 连接过多导致tomcat无法启动的解决方法
  • memcache set方法 MEMCACHE_COMPRESSED
  • if(A B || C),应该如何解释满足A、B、C之间的关系
  • Web前端开发的主要职责
  • 啊啊啊
  • 60、70后的互联网恐慌来源于圈地思维失效
  • python3的urllib2报错问题解决方法
  • mkbootimg hacking
  • linux启动常见故障
  • 一站式学习Wireshark(一):Wireshark基本用法
  • FU-A分包方式,以及从RTP包里面得到H.264数据和AAC数据的方法
  • build.gradle中buildTypes和productFlavors详解
  • Exchange Server 2010安装测试
  • Linux粘滞位的设置
  • 千万PV级别WEB站点架构设计2
  • GitUp, 你不可错过的秀外慧中的git工具
  • javascript 哈希表
  • java概述
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • Nodejs和JavaWeb协助开发
  • 从0实现一个tiny react(三)生命周期
  • 服务器从安装到部署全过程(二)
  • 高性能JavaScript阅读简记(三)
  • 巧用 TypeScript (一)
  • 我感觉这是史上最牛的防sql注入方法类
  • Android开发者必备:推荐一款助力开发的开源APP
  • Java性能优化之JVM GC(垃圾回收机制)
  • 从如何停掉 Promise 链说起
  • !!Dom4j 学习笔记
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (四)JPA - JQPL 实现增删改查
  • (一)VirtualBox安装增强功能
  • (一)基于IDEA的JAVA基础12
  • (转)Linux整合apache和tomcat构建Web服务器
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .net mvc 获取url中controller和action
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .net web项目 调用webService
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • .NET中的Exception处理(C#)
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • :not(:first-child)和:not(:last-child)的用法
  • @Repository 注解
  • @Validated和@Valid校验参数区别
  • [ C++ ] STL---stack与queue
  • [100天算法】-不同路径 III(day 73)
  • [20190113]四校联考
  • [Angular 基础] - 指令(directives)
  • [C#基础]说说lock到底锁谁?
  • [kubernetes]控制平面ETCD
  • [leetcode] 66. 加一
  • [LeetCode][LCR190]加密运算——全加器的实现