Lua教程(十七):C API简介

时间:2022-11-11 09:46:15 其他范文 收藏本文 下载本文

Lua教程(十七):C API简介(共5篇)由网友“诡计多端的小狗”投稿提供,以下是小编为大家准备的Lua教程(十七):C API简介,仅供参考,大家一起来看看吧。

Lua教程(十七):C API简介

篇1:Lua教程(十七):C API简介

这篇文章主要介绍了Lua教程(十七):C API简介,本文讲解了基础知识、栈、C API中的错误处理、Lua调用C程序、C程序调用Lua代码的错误处理等内容,需要的朋友可以参考下

Lua是一种嵌入式脚本语言,即Lua不是可以单独运行的程序,在实际应用中,主要存在两种应用形式,第一种形式是,C/C++作为主程序,调用Lua代码,此时可以将Lua看做“可扩展的语言”,我们将这种应用称为“应用程序代码”。第二种形式是Lua具有控制权,而C/C++代码则作为Lua的“库代码”。在这两种形式中,都是通过Lua提供的C API完成两种语言之间的通信的。

1. 基础知识:

C API是一组能使C/C++代码与Lua交互的函数。其中包括读写Lua全局变量、调用Lua函数、运行一段Lua代码,以及注册C函数以供Lua代码调用等。这里先给出一个简单的示例代码:

代码如下:

#include

#include

#include

#include

#include

int main(void)

{

const char* buff = “print(\”hello\“)”;

int error;

lua_State* L = luaL_newstate;

luaL_openlibs(L);

error = luaL_loadbuffer(L,buff,strlen(buff),“line”) || lua_pcall(L,0,0,0);

int s = lua_gettop(L);

if (error) {

fprintf(stderr,“%s”,lua_tostring(L,-1));

lua_pop(L,1);

}

lua_close(L);

return 0;

}

下面是针对以上代码给出的具体解释:

1). 上面的代码是基于我的C++工程,而非C工程,因此包含的头文件是lua.hpp,如果是C工程,可以直接包含lua.h。

2). Lua库中没有定义任何全局变量,而是将所有的状态都保存在动态结构lua_State中,后面所有的C API都需要该指针作为第一个参数。

3). luaL_openlibs函数是用于打开Lua中的所有标准库,如io库、string库等。

4). luaL_loadbuffer编译了buff中的Lua代码,如果没有错误,则返回0,同时将编译后的程序块压入虚拟栈中。

5). lua_pcall函数会将程序块从栈中弹出,并在保护模式下运行该程序块。执行成功返回0,否则将错误信息压入栈中。

6). lua_tostring函数中的-1,表示栈顶的索引值,栈底的索引值为1,以此类推。该函数将返回栈顶的错误信息,但是不会将其从栈中弹出。

7). lua_pop是一个宏,用于从虚拟栈中弹出指定数量的元素,这里的1表示仅弹出栈顶的元素。

8). lua_close用于释放状态指针所引用的资源。

2. 栈:

在Lua和C语言之间进行数据交换时,由于两种语言之间有着较大的差异,比如Lua是动态类型,C语言是静态类型,Lua是自动内存管理,而C语言则是手动内存管理。为了解决这些问题,Lua的设计者使用了虚拟栈作为二者之间数据交互的介质。在C/C++程序中,如果要获取Lua的值,只需调用Lua的C API函数,Lua就会将指定的值压入栈中。要将一个值传给Lua时,需要先将该值压入栈,然后调用Lua的C API,Lua就会获取该值并将其从栈中弹出。为了可以将不同类型的值压入栈,以及从栈中取出不同类型的值,Lua为每种类型均设定了一个特定函数。

1). 压入元素:

Lua针对每种C类型,都有一个C API函数与之对应,如:

代码如下:

void lua_pushnil(lua_State* L); --nil值

void lua_pushboolean(lua_State* L, int b); --布尔值

void lua_pushnumber(lua_State* L, lua_Number n); --浮点数

void lua_pushinteger(lua_State* L, lua_Integer n); --整型

void lua_pushlstring(lua_State* L, const char* s, size_t len); --指定长度的内存数据

void lua_pushstring(lua_State* L, const char* s); --以零结尾的字符串,其长度可由strlen得出。

对于字符串数据,Lua不会持有他们的指针,而是调用在API时生成一个内部副本,因此,即使在这些函数返回后立刻释放或修改这些字符串指针,也不会有任何问题。

在向栈中压入数据时,可以通过调用下面的函数判断是否有足够的栈空间可用,一般而言,Lua会预留20个槽位,对于普通应用来说已经足够了,除非是遇到有很多参数的函数。

int lua_checkstack(lua_State* L, int extra) --期望得到extra数量的空闲槽位,如果不能扩展并获得,返回false。

2). 查询元素:

API使用“索引”来引用栈中的元素,第一个压入栈的为1,第二个为2,依此类推。我们也可以使用负数作为索引值,其中-1表示为栈顶元素,-2为栈顶下面的元素,同样依此类推。

Lua提供了一组特定的函数用于检查返回元素的类型,如:

代码如下:

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);

以上函数,成功返回1,否则返回0。需要特别指出的是,对于lua_isnumber而言,不会检查值是否为数字类型,而是检查值是否能转换为数字类型。

Lua还提供了一个函数lua_type,用于获取元素的类型,函数原型如下:

代码如下:

int lua_type (lua_State *L, int index);

该函数的返回值为一组常量值,分别是:LUA_TNIL、LUA_TNUMBER、LUA_TBOOLEAN、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA、LUA_TTHREAD和LUA_TLIGHTUSERDATA,

这些常量通常用于switch语句中。

除了上述函数之外,Lua还提供了一组转换函数,如:

代码如下:

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);

--string类型返回字符串长度,table类型返回操作符‘#‘等同的结果,userdata类型返回分配的内存块长度。

size_t lua_objlen (lua_State *L, int index);

对于上述函数,如果调用失败,lua_toboolean、lua_tonumber、lua_tointeger和lua_objlen均返回0,而其他函数则返回NULL。在很多时候0不是一个很有效的用于判断错误的值,但是ANSI C没有提供其他可以表示错误的值。因此对于这些函数,在有些情况下需要先使用lua_is*系列函数判断是否类型正确,而对于剩下的函数,则可以直接通过判断返回值是否为NULL即可。

对于lua_tolstring函数返回的指向内部字符串的指针,在该索引指向的元素被弹出之后,将无法保证仍然有效。该函数返回的字符串末尾均会有一个尾部0。

下面将给出一个工具函数,可用于演示上面提到的部分函数,如:

代码如下:

static void stackDump(lua_State* L)

{

int top = lua_gettop(L);

for (int i = 1; i <= top; ++i) {

int t = lua_type(L,i);

switch(t) {

case LUA_TSTRING:

printf(“‘%s‘”,lua_tostring(L,i));

break;

case LUA_TBOOLEAN:

printf(lua_toboolean(L,i) ? “true” : “false”);

break;

case LUA_TNUMBER:

printf(“%g”,lua_tonumber(L,i));

break;

default:

printf(“%s”,lua_typename(L,t));

break;

}

printf(“”);

}

printf(“\n”);

}

3). 其它栈操作函数:

除了上面给出的数据交换函数之外,Lua的C API还提供了一组用于操作虚拟栈的普通函数,如:

代码如下:

int lua_gettop(lua_State* L); --返回栈中元素的个数。

void lua_settop(lua_State* L, int index); --将栈顶设置为指定的索引值。

void lua_pushvalue(lua_State* L, int index); --将指定索引的元素副本压入栈。

void lua_remove(lua_State* L, int index); --删除指定索引上的元素,其上面的元素自动下移。

void lua_insert(lua_State* L, int index); --将栈顶元素插入到该索引值指向的位置。

void lua_replace(lua_State* L, int index); --弹出栈顶元素,并将该值设置到指定索引上。

Lua还提供了一个宏用于弹出指定数量的元素:

代码如下:

#define lua_pop(L,n) lua_settop(L, -(n) - 1)

见如下示例代码:

代码如下:

int main()

{

lua_State* L = luaL_newstate();

lua_pushboolean(L,1);

lua_pushnumber(L,10);

lua_pushnil(L);

lua_pushstring(L,“hello”);

stackDump(L); //true 10 nil ‘hello‘

lua_pushvalue(L,-4);

stackDump(L); //true 10 nil ‘hello‘ true

lua_replace(L,3);

stackDump(L); //true 10 true ‘hello‘

lua_settop(L,6);

stackDump(L); //true 10 true ‘hello‘ nil nil

lua_remove(L,-3);

stackDump(L); //true 10 true nil nil

lua_settop(L,-5);

stackDump(L); //true

lua_close(L);

return 0;

}

3. C API中的错误处理:

1). C程序调用Lua代码的错误处理:

通常情况下,应用程序代码是以“无保护”模式运行的。因此,当Lua发现“内存不足”这类错误时,只能通过调用“紧急”函数来通知C语言程序,之后在结束应用程序。用户可通过lua_atpanic来设置自己的“紧急”函数。如果希望应用程序代码在发生Lua错误时不会退出,可通过调用lua_pcall函数以保护模式运行Lua代码。这样再发生内存错误时,lua_pcall会返回一个错误代码,并将解释器重置为一致的状态。如果要保护与Lua的C代码,可以使用lua_cpall函数,它将接受一个C函数作为参数,然后调用这个C函数。

2). Lua调用C程序:

通常而言,当一个被Lua调用的C函数检测到错误时,它就应该调用lua_error,该函数会清理Lua中所有需要清理的资源,然后跳转回发起执行的那个lua_pcall,并附上一条错误信息。

篇2:Lua教程(二十二):userdata

这篇文章主要介绍了Lua教程(二十二):userdata,这里我们通过一个简单完整的示例来学习一下Lua中userdata的使用方式,需要的朋友可以参考下

在Lua中可以通过自定义类型的方式与C语言代码更高效、更灵活的交互,这里我们通过一个简单完整的示例来学习一下Lua中userdata的使用方式。需要说明的是,该示例完全来自于Programming in Lua。其功能是用C程序实现一个Lua的布尔数组,以提供程序的执行效率。见下面的代码和关键性注释。

代码如下:

#include

#include

#include

#include

#define BITS_PER_WORD (CHAR_BIT * sizeof(int))

#define I_WORD(i)    ((unsigned int)(i))/BITS_PER_WORD

#define I_BIT(i)     (1 << ((unsigned int)(i)%BITS_PER_WORD))

typedef struct NumArray {

int size;

unsigned int values[1];

} NumArray;

extern “C” int newArray(lua_State* L)

{

//1. 检查第一个参数是否为整型。以及该参数的值是否大于等于1.

int n = luaL_checkint(L,1);

luaL_argcheck(L, n >= 1, 1, “invalid size.”);

size_t nbytes = sizeof(NumArray) + I_WORD(n - 1) * sizeof(int);

//2. 参数表示Lua为userdata分配的字节数。同时将分配后的userdata对象压入栈中。

NumArray* a = (NumArray*)lua_newuserdata(L,nbytes);

a->size = n;

for (int i = 0; i < I_WORD(n - 1); ++i)

a->values[i] = 0;

//获取注册表变量myarray,该key的值为metatable。

luaL_getmetatable(L,“myarray”);

//将userdata的元表设置为和myarray关联的table。同时将栈顶元素弹出。

lua_setmetatable(L,-2);

return 1;

}

extern “C” int setArray(lua_State* L)

{

//1. Lua传给该函数的第一个参数必须是userdata,该对象的元表也必须是注册表中和myarray关联的table。

//否则该函数报错并终止程序。

NumArray* a = (NumArray*)luaL_checkudata(L,1,“myarray”);

int index = luaL_checkint(L,2) - 1;

//2. 由于任何类型的数据都可以成为布尔值,因此这里使用any只是为了确保有3个参数。

luaL_checkany(L,3);

luaL_argcheck(L,a != NULL,1,“‘array‘ expected.”);

luaL_argcheck(L,0 <= index && index < a->size,2,“index out of range.”);

if (lua_toboolean(L,3))

a->values[I_WORD(index)] |= I_BIT(index);

else

a->values[I_WORD(index)] &= ~I_BIT(index);

return 0;

}

extern “C” int getArray(lua_State* L)

{

NumArray* a = (NumArray*)luaL_checkudata(L,1,“myarray”);

int index = luaL_checkint(L,2) - 1;

luaL_argcheck(L, a != NULL, 1, “‘array‘ expected.”);

luaL_argcheck(L, 0 <= index && index < a->size,2,“index out of range”);

lua_pushboolean(L,a->values[I_WORD(index)] & I_BIT(index));

return 1;

}

extern “C” int getSize(lua_State* L)

{

NumArray* a = (NumArray*)luaL_checkudata(L,1,“myarray”);

luaL_argcheck(L,a != NULL,1,“‘array‘ expected.”);

lua_pushinteger(L,a->size);

return 1;

}

extern “C” int array2string(lua_State* L)

{

NumArray* a = (NumArray*)luaL_checkudata(L,1,“myarray”);

lua_pushfstring(L,“array(%d)”,a->size);

return 1;

}

static luaL_Reg arraylib_f [] = {

{“new”, newArray},

{NULL, NULL}

};

static luaL_Reg arraylib_m [] = {

{“set”, setArray},

{“get”, getArray},

{“size”, getSize},

{“__tostring”, array2string}, //print(a)时Lua会调用该元方法,

{NULL, NULL}

};

extern “C” __declspec(dllexport)

int luaopen_testuserdata(lua_State* L)

{

//1. 创建元表,并将该元表指定给newArray函数新创建的userdata。在Lua中userdata也是以table的身份表现的。

//这样在调用对象函数时,可以通过验证其metatable的名称来确定参数userdata是否合法。

luaL_newmetatable(L,“myarray”);

lua_pushvalue(L,-1);

//2. 为了实现面对对象的调用方式,需要将元表的__index字段指向自身,同时再将arraylib_m数组中的函数注册到

//元表中,之后基于这些注册函数的调用就可以以面向对象的形式调用了。

//lua_setfield在执行后会将栈顶的table弹出。

lua_setfield(L,-2,“__index”);

//将这些成员函数注册给元表,以保证Lua在寻找方法时可以定位。NULL参数表示将用栈顶的table代替第二个参数。

luaL_register(L,NULL,arraylib_m);

//这里只注册的工厂方法。

luaL_register(L,“testuserdata”,arraylib_f);

return 1;

}

轻量级userdata:

之前介绍的是full userdata,Lua还提供了另一种轻量级userdata(light userdata)。事实上,轻量级userdata仅仅表示的是C指针的值,即(void*)。由于它只是一个值,所以不用创建。如果需要将一个轻量级userdata放入栈中,调用lua_pushlightuserdata即可。full userdata和light userdata之间最大的区别来自于相等性判断,对于一个full userdata,它只是与自身相等,而light userdata则表示为一个C指针,因此,它与所有表示同一指针的light userdata相等。再有就是light userdata不会受到垃圾收集器的管理,使用时就像一个普通的整型数字一样。

篇3:Lua教程(十九):C调用Lua

这篇文章主要介绍了Lua教程(十九):C调用Lua,本文讲解了C调用Lua基础知识、table操作、调用Lua函数等内容,需要的朋友可以参考下

1. 基础:

Lua的一项重要用途就是作为一种配置语言,现在从一个简单的示例开始吧。

代码如下:

--这里是用Lua代码定义的窗口大小的配置信息

width = 200

height = 300

下面是读取配置信息的C/C++代码:

代码如下:

#include

#include

#include

#include

#include

void load(lua_State* L, const char* fname, int* w, int* h) {

if (luaL_loadfile(L,fname) || lua_pcall(L,0,0,0)) {

printf(“Error Msg is %s.\n”,lua_tostring(L,-1));

return;

}

lua_getglobal(L,“width”);

lua_getglobal(L,“height”);

if (!lua_isnumber(L,-2)) {

printf(“‘width‘ should be a number\n” );

return;

}

if (!lua_isnumber(L,-1)) {

printf(“‘height‘ should be a number\n” );

return;

}

*w = lua_tointeger(L,-2);

*h = lua_tointeger(L,-1);

}

int main

{

lua_State* L = luaL_newstate();

int w,h;

load(L,“D:/test.lua”,&w,&h);

printf(“width = %d, height = %d\n”,w,h);

lua_close(L);

return 0;

}

下面是针对新函数的解释:

lua_getglobal是宏,其原型为:#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))。

每次调用这个宏的时候,都会将Lua代码中与之相应的全局变量值压入栈中,第一次调用时将全局变量“width”的值压入栈中,之后再次调用时再将“height”的值也压入栈中。

2. table操作:

我们可以在C语言的代码中操作Lua中的table数据,这是一个非常非常方便且实用的功能。这样不仅可以使Lua代码的结构更加清晰,也可以在C语言代码中定义等同的结构体与之对应,从而大大提高代码的可读性。见如下代码:

代码如下:

#include

#include

#include

#include

#include

void load(lua_State* L) {

if (luaL_loadstring(L,“background = { r = 0.30, g = 0.10, b = 0 }”)

|| lua_pcall(L,0,0,0)) {

printf(“Error Msg is %s.\n”,lua_tostring(L,-1));

return;

}

lua_getglobal(L,“background”);

if (!lua_istable(L,-1)) {

printf(“‘background‘ is not a table.\n” );

return;

}

lua_getfield(L,-1,“r”);

if (!lua_isnumber(L,-1)) {

printf(“Invalid component in background color.\n”);

return;

}

int r = (int)(lua_tonumber(L,-1) * 255);

lua_pop(L,1);

lua_getfield(L,-1,“g”);

if (!lua_isnumber(L,-1)) {

printf(“Invalid component in background color.\n”);

return;

}

int g = (int)(lua_tonumber(L,-1) * 255);

lua_pop(L,1);

lua_pushnumber(L,0.4);

lua_setfield(L,-2,“b”);

lua_getfield(L,-1,“b”);

if (!lua_isnumber(L,-1)) {

printf(“Invalid component in background color.\n”);

return;

}

int b = (int)(lua_tonumber(L,-1) * 255);

printf(“r = %d, g = %d, b = %d\n”,r,g,b);

lua_pop(L,1);

lua_pop(L,1);

return;

}

int main()

{

lua_State* L = luaL_newstate();

load(L);

lua_close(L);

return 0;

}

void lua_getfield(lua_State *L, int idx, const char *k); 第二个参数是table变量在栈中的索引值,最后一个参数是table的键值,该函数执行成功后会将字段值压入栈中。

void lua_setfield(lua_State *L, int idx, const char *k); 第二个参数是table变量在栈中的索引值,最后一个参数是table的键名称,而字段值是通过上一条命令lua_pushnumber(L,0.4)压入到栈中的,该函数在执行成功后会将刚刚压入的字段值弹出栈,

下面的代码示例是在C语言代码中构造table对象,同时初始化table的字段值,最后再将table对象赋值给Lua中的一个全局变量。

代码如下:

#include

#include

#include

#include

#include

void load(lua_State* L)

{

lua_newtable(L);

lua_pushnumber(L,0.3);

lua_setfield(L,-2,“r”);

lua_pushnumber(L,0.1);

lua_setfield(L,-2,“g”);

lua_pushnumber(L,0.4);

lua_setfield(L,-2,“b”);

lua_setglobal(L,“background”);

lua_getglobal(L,“background”);

if (!lua_istable(L,-1)) {

printf(“‘background‘ is not a table.\n” );

return;

}

lua_getfield(L,-1,“r”);

if (!lua_isnumber(L,-1)) {

printf(“Invalid component in background color.\n”);

return;

}

int r = (int)(lua_tonumber(L,-1) * 255);

lua_pop(L,1);

lua_getfield(L,-1,“g”);

if (!lua_isnumber(L,-1)) {

printf(“Invalid component in background color.\n”);

return;

}

int g = (int)(lua_tonumber(L,-1) * 255);

lua_pop(L,1);

lua_getfield(L,-1,“b”);

if (!lua_isnumber(L,-1)) {

printf(“Invalid component in background color.\n”);

return;

}

int b = (int)(lua_tonumber(L,-1) * 255);

printf(“r = %d, g = %d, b = %d\n”,r,g,b);

lua_pop(L,1);

lua_pop(L,1);

return;

}

int main()

{

lua_State* L = luaL_newstate();

load(L);

lua_close(L);

return 0;

}

上面的代码将输出和之前代码相同的结果。

lua_newtable是宏,其原型为:#define lua_newtable(L) lua_createtable(L, 0, 0)。调用该宏后,Lua会生成一个新的table对象并将其压入栈中。

lua_setglobal是宏,其原型为:#define lua_setglobal(L,s) lua_setfield(L,LUA_GLOBALSINDEX,(s))。调用该宏后,Lua会将当前栈顶的值赋值给第二个参数指定的全局变量名。该宏在执行成功后,会将刚刚赋值的值从栈顶弹出。

3. 调用Lua函数:

调用函数的API也很简单。首先将待调用函数压入栈,再压入函数的参数,然后使用lua_pcall进行实际的调用,最后将调用结果从栈中弹出。见如下代码:

代码如下:

#include

#include

#include

#include

#include

const char* lua_function_code = “function add(x,y) return x + y end”;

void call_function(lua_State* L)

{

//luaL_dostring 等同于luaL_loadstring() || lua_pcall()

//注意:在能够调用Lua函数之前必须执行Lua脚本,否则在后面实际调用Lua函数时会报错,

//错误信息为:“attempt to call a nil value.”

if (luaL_dostring(L,lua_function_code)) {

printf(“Failed to run lua code.\n”);

return;

}

double x = 1.0, y = 2.3;

lua_getglobal(L,“add”);

lua_pushnumber(L,x);

lua_pushnumber(L,y);

//下面的第二个参数表示带调用的lua函数存在两个参数。

//第三个参数表示即使带调用的函数存在多个返回值,那么也只有一个在执行后会被压入栈中。

//lua_pcall调用后,虚拟栈中的函数参数和函数名均被弹出。

if (lua_pcall(L,2,1,0)) {

printf(“error is %s.\n”,lua_tostring(L,-1));

return;

}

//此时结果已经被压入栈中。

if (!lua_isnumber(L,-1)) {

printf(“function ‘add‘ must return a number.\n”);

return;

}

double ret = lua_tonumber(L,-1);

lua_pop(L,-1); //弹出返回值。

printf(“The result of call function is %f.\n”,ret);

}

int main()

{

lua_State* L = luaL_newstate();

call_function(L);

lua_close(L);

return 0;

}

篇4:Lua教程(三):表达式和语句

这篇文章主要介绍了Lua教程(三):表达式和语句,本文讲解了算术操作符、关系操作符、逻辑操作符、字符串连接、table构造器、控制结构等内容,需要的朋友可以参考下

一、表达式:

1. 算术操作符:

Lua支持常规算术操作符有:二元的“+”、“-”、“*”、“/”、“^”(指数)、“%”(取模),一元的“-”(负号),所有这些操作符都可用于实数。然而需要特别说明的是取模操作符(%),Lua中对该操作符的定义为:

代码如下:

a % b == a - floor(a / b) * b

由此可以推演出x % 1的结果为x的小数部分,而x - x % 1的结果则为x的整数部分。类似的,x - x % 0.01则是x精确到小数点后两位的结果。

2. 关系操作符:

Lua支持的关系操作符有:>、<、>=、<=、==、~=,所有这些操作符的结果均为true或false。

操作符==用于相等性测试,操作符~=用于不等性测试。这两个操作符可以应用于任意两个值。如果两个值的类型不同,Lua就认为他们不等。nil值与其自身相等。对于table、userdata和函数,Lua是通过引用进行比较的。也就是说,只有当他们引用同一个对象时,才视为相等。如:

代码如下:

a = {}

a.x = 1

a.y = 0

b = {}

b.x = 1

b.y = 1

c = a

其结果是a == c,但a ~= b。

对于字符串的比较,Lua是按照字符次序比较的。

3. 逻辑操作符:

Lua支持的逻辑操作符有:and、or和not。与条件控制语句一样,所有的逻辑操作符都将false和nil视为假,其他的结果均为真。和其他大多数语言一样,Lua中的and和or都使用“短路原则”。在Lua中有一种惯用写法“x = x or v”,它等价于:if not x then x = v end。这里还有一种基于“短路原则”的惯用写法,如:

代码如下:

max = (x >y) and x or y

这等价于C语言中max = (x >y) ? x : y。由于x和y均为数值,因此它们的结果将始终为true。

4. 字符串连接:

前一篇Blog已经提到了字符串连接操作符(..),这里再给出一些简单的示例。

代码如下:

/>lua

>print(“Hello ” .. “World)

Hello World

>print(0 .. 1) --即使连接操作符的操作数为数值类型,在执行时Lua仍会将其自动转换为字符串。

01

5. table构造器:

构造器用于构建和初始化table的表达式。这是Lua特有的表达式,也是Lua中最有用、最通用的机制之一。其中最简单的构造器是空构造器{},用于创建空table。我们通过构造器还可以初始化数组,如:

代码如下:

days = {”Sunday“,”Monday“,”Tuesday“,”Wednesday“,”Thursday“,”Friday“,”Saturday“}

for i = 1,#days do

print(days[i])

end

--输出结果为

--Sunday

--Monday

--Tuesday

--Wednesday

--Thursday

--Friday

--Saturday

从输出结果可以看出,days在构造后会将自动初始化,其中days[1]被初始化为”Sunday“,days[2]为”Monday“,以此类推。

Lua中还提供了另外一种特殊的语法用于初始化记录风格的table。如:a = { x = 10, y = 20 },其等价于:a = {}; a.x = 10; a.y = 20

在实际编程时我们也可以将这两种初始化方式组合在一起使用,如:

代码如下:

polyline = {color = ”blue“, thickness = 2, npoints = 4,

{x = 0, y = 0},

{x = 10, y = 0},

{x = -10, y = 1},

{x = 0, y = 1} }

print(polyline[”color“]);

print(polyline[2].x)

print(polyline[4].y)

--输出结果如下:

--blue

--10

--1

除了以上两种构造初始化方式之外,Lua还提供另外一种更为通用的方式,如:

代码如下:

pnames = { [”+“] = ”add“, [”-“] = ”sub“, [”*“] = ”mul“, [”/“] = ”div“}

print(opnames[”+“])

i = 20; s = ”-“

a = { [i + 0] = s, [i + 1] = s .. s, [i + 2] = s..s..s }

print(a[22])

对于table的构造器,还有两个需要了解的语法规则,如:

代码如下:

a = { [1] = ”red“, [2] = ”green“, [3] = ”blue“, }

这里需要注意最后一个元素的后面仍然可以保留逗号(,),这一点类似于C语言中的枚举。

代码如下:

a = {x = 10, y = 45; ”one“, ”two“, ”three“ }

可以看到上面的声明中同时存在逗号(,)和分号(;)两种元素分隔符,这种写法在Lua中是允许的,

我们通常会将分号(;)用于分隔不同初始化类型的元素,如上例中分号之前的初始化方式为记录初始化方式,而后面则是数组初始化方式。

二、语句:

1. 赋值语句:

Lua中的赋值语句和其它编程语言基本相同,唯一的差别是Lua支持“多重赋值”,如:a, b = 10, 2 * x,其等价于a = 10; b = 2 * x。然而需要说明的是,Lua在赋值之前需要先计算等号右边的表达式,在每一个表达式都得到结果之后再进行赋值。因此,我们可以这样写变量交互:x,y = y,x。如果等号右侧的表达式数量少于左侧变量的数量,Lua会将左侧多出的变量的值置为nil,如果相反,Lua将忽略右侧多出的表达式。

2. 局部变量与块:

Lua中的局部变量定义语法为:local i = 1,其中local关键字表示该变量为局部变量。和全局变量不同的是,局部变量的作用范围仅限于其所在的程序块。Lua中的程序可以为控制结构的执行体、函数执行体或者是一个程序块,如:

下面的x变量仅在while循环内有效。

代码如下:

while i <= x do

local x = i * 2

print(x)

i = i + 1

end

如果是在交互模式下,当执行local x = 0之后,该变量x所在的程序即以结束,后面的Lua语句将被视为新的程序块。如果想避免此类问题,我们可以显式的声明程序块,这样即便是在交互模式下,局部变量仍然能保持其块内有效性,如:

代码如下:

do

local a2 = 2 * a

local d = (b ^ 2 - 4 * a) ^ (1 / 2)

x1 = (-b + d) / a2

x2 = (-b - d) / a2

end --a2和d的作用域至此结束。

和其它编程语言一样,如果有可能尽量使用局部变量,以免造成全局环境的变量名污染。同时由于局部变量的有效期更短,这样垃圾收集器可以及时对其进行清理,从而得到更多的可用内存。

3. 控制结构:

Lua中提供的控制语句和其它大多数开发语言所提供的基本相同,因此这里仅仅是进行简单的列举。然后再给出差异部分的详细介绍。如:

1). if then else

代码如下:

if a < 0 then

b = 0

else

b = 1

end

2). if elseif else then

代码如下:

if a < 0 then

b = 0

elseif a == 0 then

b = 1

else

b = 2

end

3). while

代码如下:

local i= 1

while a[i] do

print(a[i])

i = i + 1

end

4). repeat

代码如下:

repeat

line = io.read()

until line ~= ”“ --直到until的条件为真时结束。

print(line)

5). for

代码如下:

for var = begin, end, step do --如果没有step变量,begin的缺省步长为1。

i = i + 1

end

需要说明的是,for循环开始处的三个变量begin、end和step,如果它们使表达式的返回值,那么该表达式将仅执行一次。再有就是不要在for的循环体内修改变量var的值,否则会导致不可预知的结果。

6). foreach

代码如下:

for i, v in ipairs(a) do --ipairs是Lua自带的系统函数,返回遍历数组的迭代器。

print(v)

end

for k in pairs(t) do     --打印table t中的所有key。

print(k)

end

见如下示例代码:

代码如下:

days = {”Sunday“, ”Monday“, ”Tuesday“, ”Wednesday“, ”Thursday“, ”Friday“, ”Saturday“ }

revDays = {}

for k, v in ipairs(days) do

revDays[v] = k

end

for k in pairs(revDays) do

print(k .. ” = " .. revDays[k])

end

--输出结果为:

--Saturday = 7

--Tuesday = 3

--Wednesday = 4

--Friday = 6

--Sunday = 1

--Thursday = 5

--Monday = 2

7). break

和C语言中的break语义完全相同,即跳出最内层循环。

篇5:Lua教程(一):Lua脚本语言介绍

这篇文章主要介绍了Lua教程(一):Lua脚本语言介绍,需要的朋友可以参考下

Lua 是一个扩展式程序设计语言,它被设计成支持通用的过程式编程,并有相关数据描述的设施, Lua 也能对面向对象编程,函数式编程,数据驱动式编程提供很好的支持。 它可以作为一个强大、轻量的脚本语言,供任何需要的程序使用。 Lua 以一个用 clean C 写成的库形式提供。(所谓 Clean C ,指的 ANSI C 和 C++ 中共通的一个子集)

作为一个扩展式语言,Lua 没有 “main” 程序的概念:它只能 嵌入 一个宿主程序中工作,这个宿主程序被称作 embedding program 或简称为 host ,

宿主程序可以通过调用函数执行一小段 Lua 代码,可以读写 Lua 变量,可以注入 C 函数让 Lua 代码调用。 这些扩展的 C 函数,可以大大的扩展了 Lua 可以处理事务的领域,这样就可以订制出各种语言, 而它们共享一个统一的句法格式的框架。 Lua 的官方发布版就包含了一个叫做 lua 的简单的宿主程序,它用 Lua 库提供了一个保证独立的 Lua 解释器。

Lua 是一个自由软件,它的使用许可决定了对它的使用过程一般没有任何保证。 这份手册中描述的东西的实现,可以在 Lua 的 www.lua.org 找到,

跟其它的许多参考手册一样,这份文档有些地方比较枯燥。 关于 Lua 的设计想法的探讨,可以看看 Lua 网站上提供的技术论文。 有关用 Lua 编程的细节介绍,可以读一下 Roberto 的书,Programming in Lua (Second Edition) 。

Lua数据类型介绍

程序开发中异常的理解及处理异常论文

详解Lua中repeat...until循环语句的使用方法

Lua的编译、执行和调试技术介绍

Lua时间转化的几个小例子

Lua 学习笔记之C API 遍历 Table实现代码

第六章 计划与计划工作 学习笔记

flex 遍历Object对象内容的实现代码

C语言中函数的返回值

C语言sprintf与sscanf函数

Lua教程(十七):C API简介
《Lua教程(十七):C API简介.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

【Lua教程(十七):C API简介(共5篇)】相关文章:

杏花春雨湿信风2022-10-05

理科毕业生简历自我评价2023-10-13

c语言函数知识点总结2023-04-03

收信日记2022-06-11

FreePOPs实现Gmail客户端收信2022-11-13

提供思考和帮助《逆商》读书笔记2022-11-10

计算机专业策划书范文2023-02-26

nosql数据库 tiger2023-07-02

关于创业时机的文章2023-09-29

豆蔻年华,谢谢你们陪着我现代诗歌欣赏2022-12-30

点击下载本文文档