读书笔记: Programming in Lua, 4th Edition.
print(8*9, 9/8)
a = math.sin(3) + math.cos(10)
print(os.date())
-- add the elements of sequence 'a'
function add (a)
local sum = 0
for i = 1, #a do
sum = sum + a[i]
end
return sum
end
if the function has one single argument and that argument is either a literal string or a table constructor, then the parentheses are optional:
如果函数只有一个参数,并且这个参数是字符串或者是table的话,函数的括号()可以省略。
print "Hello World" <--> print("Hello World")
dofile 'a.lua' <--> dofile ('a.lua')
print [[a multi-line <--> print([[a multi-line
message]] message]])
f{x=10, y=20} <--> f({x=10, y=20})
type{} <--> type({})
We can call a function with a number of arguments different from its number of parameters. Lua adjusts the number of arguments to the number of parameters by throwing away extra arguments and supplying nils to extra parameters. For instance, consider the next function:
函数调用时提供的参数可以和函数定义时的参数个数不同。不足的用nil补全,多余的话会被自动忽略。
function f (a, b)
print(a, b)
end
f() --> nil nil
f(3) --> 3 nil
f(3, 4) --> 3 4
f(3, 4, 5) --> 3 4 (5 is discarded)
function incCount (n)
n = n or 1
globalCounter = globalCounter + n
end
function maximum (a)
local mi = 1 -- index of the maximum value
local m = a[mi] -- maximum value
for i = 1, #a do
if a[i] > m then
mi = i; m = a[i]
end
end
return m, mi -- return the maximum and its index
end
print(maximum({8,10,23,12,5})) --> 23 3
Lua always adjusts the number of results from a function to the circumstances of the call.
When we call a function as a statement, Lua discards all results from the function.
When we use a call as an expression (e.g., the operand of an addition), Lua keeps only the first result.
We get all results only when the call is the last (or the only) expression in a list of expressions.
function foo0 () end -- returns no results
function foo1 () return "a" end -- returns 1 result
function foo2 () return "a", "b" end -- returns 2 results
x, y = foo2() -- x="a", y="b"
x = foo2() -- x="a", "b" is discarded
x, y, z = 10, foo2() -- x=10, y="a", z="b"
x,y = foo0() -- x=nil, y=nil
x,y = foo1() -- x="a", y=nil
x,y,z = foo2() -- x="a", y="b", z=nil
Remember that multiple results only happen when the call is the last (or only) expression in a list. A function call that is not the last element in the list always produces exactly one result:
x,y = foo2(), 20 -- x="a", y=20 ('b' discarded)
x,y = foo0(), 20, 30 -- x=nil, y=20 (30 is discarded)
print(foo0()) --> (no results)
print(foo1()) --> a
print(foo2()) --> a b
print(foo2(), 1) --> a 1
print(foo2() .. "x") --> ax (see next)
A constructor also collects all results from a call, without any adjustments:
t = {foo0()} -- t = {} (an empty table)
t = {foo1()} -- t = {"a"}
t = {foo2()} -- t = {"a", "b"}
As always, this behavior happens only when the call is the last expression in the list; calls in any other position produce exactly one result:
t = {foo0(), foo2(), 4} -- t[1] = nil, t[2] = "a", t[3] = 4
We can force a call to return exactly one result by enclosing it in an extra pair of parentheses:
print((foo0())) --> nil
print((foo1())) --> a
print((foo2())) --> a
function add(...)
local s = 0
for _, v in ipairs{...} do
s = s + v
end
return s
end
print(add(3, 4, 10, 25, 12)) --> 54
Lua offers the function table.pack.1 This function receives any number of arguments and returns a new table with all its arguments (just like {…}), but this table has also an extra field “n”, with the total number of arguments.
function nonils(...)
local arg = table.pack(...)
for i = 1, arg.n do
if arg[i] == nil then
return false
end
end
return true
end
print(nonils(2,3,nil)) --> false
print(nonils(2,3)) --> true
print(nonils()) --> true
print(nonils(nil)) --> false
A call to select has always one fixed argument, the selector, plus a variable number of extra arguments. If the selector is a number n, select returns all arguments after the n-th argument; otherwise, the selector should be the string “#”, so that select returns the total number of extra arguments.
print(select(1, "a", "b", "c")) --> a b c
print(select(2, "a", "b", "c")) --> b c
print(select(3, "a", "b", "c")) --> c
print(select("#", "a", "b", "c")) --> 3
function add (...)
local s = 0
for i = 1, select("#", ...) do
s = s + select(i, ...)
end
return s
end
A special function with multiple returns is table.unpack. It takes a list and returns as results all elements from the list:
print(table.unpack{10,20,30}) --> 10 20 30
a,b = table.unpack{10,20,30} -- a=10, b=20, 30 is discarded
As the name implies, table.unpack is the reverse of table.pack. While pack transforms a parameter list into a real Lua list (a table), unpack transforms a real Lua list (a table) into a return list, which can be given as the parameter list to another function.
function unpack (t, i, n)
i = i or 1
n = n or #t
if i <= n then
return t[i], unpack(t, i + 1, n)
end
end
尾调用:也就是在一个函数A的最后调用一个函数B,因为函数A已经执行完了,所以函数B可以重复利用A的栈空间,提高效率。
读书笔记: Programming in Lua, 4th Edition.
N = 8 -- board size
-- check whether position (n,c) is free from attacks
function isplaceok(a , n , c)
for i = 1, n - 1 do
if (a[i] == c) or
(a[i] - i == c - n) or
(a[i] + i == c + n) then
return false --place can be attacked
end
end
return true --no attacks; place is ok
end
-- print a board
function printsolution( a )
for i = 1, N do
for j = 1, N do
io.write(a[i] == j and "X" or "-", " ")
end
io.write("\n")
end
io.write("\n")
end
-- add to board 'a' all queens from 'n' to 'N'
function addqueen( a, n )
if n > N then
printsolution(a)
else
for c = 1, N do
if isplaceok(a, n, c) then
a[n] = c
addqueen(a, n + 1)
end
end
end
end
addqueen({}, 1)
单行注释用 –
多行注释用 –[[]]
官网地址:
Lua是脚本语言,可以自己运行,可以嵌入C语言运行,也可以把C语言嵌入Lua运行。
Lua全部都是用C语言实现的,可以到官网去下载源码,自己编译,编译过程很简单,没什么错误。
源码目录结构:
需要在VS中新建一个VC++解决方案,在该解决方案下建3个项目,分别是lua库项目,lua编译器项目,lua解释器项目。
Lua53 是库项目,生成Lua53.lib。
Lua 是解释器项目,生成Lua.exe。
Luac 是编译器项目,生成Luac.exe。
最终要生成的文件如下:
打开VS2013(其他版本亦可),新建VisuallC++ ->win32控制台应用程序,修改项目名称为Lua53,然后再点击确定。
点击下一步,选择静态库,空项目,点击完成。
将src目录下除了lua.c和luac.c其他所有文件加入lua53工程下的源文件目录
打开VS2013(其他版本亦可),新建VisuallC++ ->win32控制台应用程序,修改项目名称为Luac,然后再点击确定。
点击下一步,选择控制台应用程序,空项目,点击完成。
将src目录下除了lua.c其他所有文件加入lua53工程下的源文件目录
打开VS2013(其他版本亦可),新建VisuallC++ ->win32控制台应用程序,修改项目名称为Lua,然后再点击确定。
点击下一步,选择控制台应用程序,空项目,点击完成。
将src目录下除了luac.c其他所有文件加入lua53工程下的源文件目录
最终我们会得到Lua53.lib, Luac.exe, Lua.exe。那要怎么使用呢?
Lua.exe 是一个交互式的命令行解释器,可以直接双击打开。
Luac.exe 是编译器。
新建一个Hello.lua,执行
Lua53.lib 是一个库文件,如果想要在C语言中嵌入Lua的话,就需要把这个文件加入到C语言的项目中。
读书笔记: Programming in Lua, 4th Edition.
There are eight basic types in Lua: nil, Boolean, number, string, userdata, function, thread, and table.
> type(nil) --> nil
> type(true) --> boolean
> type(10.4 * 3) --> number
> type("Hello world") --> string
> type(io.stdin) --> userdata
> type(print) --> function
> type(type) --> function
> type({}) --> table
> type(type(X)) --> string
Conditional tests consider both the Boolean false and nil as false and anything else as true. In particular, Lua considers both zero and the empty string as true in conditional tests.
The result of the and operator is its first operand if that operand is false; otherwise, the result is its second operand.
The result of the or operator is its first operand if it is not false; otherwise, the result is its second operand
> 4 and 5 --> 5
> nil and 13 --> nil
> false and 13 --> false
> 0 or 5 --> 0
> false or "hi" --> "hi"
> nil or false --> false
The not operator always gives a Boolean value:
> not nil --> true
> not false --> true
> not 0 --> false
> not not 1 --> true
> not not nil --> false
A useful Lua idiom is x = x or v, which is equivalent to (if not x then x = v end).
Another useful idiom is ((a and b) or c) or simply (a and b or c) (given that and has a higher precedence than or). It is equivalent to the C expression a ? b : c.
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
#ifdef __KERNEL__
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head * new,
struct list_head * prev,
struct list_head * next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head * prev,
struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is in an undefined state.
*/
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static __inline__ void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list, struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#endif /* __KERNEL__ */
#endif
#include <stdio.h>
struct Node {
int i;
int j;
int k;
};
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
int main()
{
struct Node stNode;
//使用场景:现在我有一个指向结构体内部成员的指针,这个时候我想要知道结构体的地址。
int * ptr = &stNode.j;
struct Node * pstNode = list_entry(ptr, struct Node, j);
printf("&stNode = %p.\n", &stNode);
printf("pstNode = %p.\n", pstNode);
return 0;
}