您的位置:首页 > 编程语言 > Lua

lua52 C API测试代码

2014-02-27 19:40 323 查看
//这是一篇lua与C++交互的情景测试


#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>
#include <string.h>
#include <limits.h>

#pragma region not_importent_
static void stackDump (lua_State *L)
{
int i;
int top = lua_gettop(L);
for(i=1;i<=top;i++){
/*repeatforeachlevel*/
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING:
/* strings */
printf("`%s'", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
/* booleans */
printf(lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER:
/* numbers */
printf("%g", lua_tonumber(L, i));
break;
default:
/* other values */
printf("%s", lua_typename(L, t));
break;
}
printf(" ");
/* put a separator */
}
printf("\n");
/* end the listing */
}

void error (lua_State *L, const char *fmt, const char *str) {
printf(fmt, str);
}
//待Lua调用的C注册函数。
static int add2(lua_State* L)
{
//检查栈中的参数是否合法,1表示Lua调用时的第一个参数(从左到右),依此类推。
//如果Lua代码在调用时传递的参数不为number,该函数将报错并终止程序的执行。
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
//将函数的结果压入栈中。如果有多个返回值,可以在这里多次压入栈中。
lua_pushnumber(L,op1 + op2);
//返回值用于提示该C函数的返回值数量,即压入栈中的返回值数量。
return 1;
}
static int sub2(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 - op2);
return 1;
}
#pragma endregion

//////////////////////////////////////////////////////////////////////////
void test_c_call_lua_fun_noParam()
{
const char* buff = "print(\"hello\")";
int err;

//init
lua_State* L = luaL_newstate();
luaL_openlibs(L);

//load buff
err = luaL_loadbuffer(L,buff,strlen(buff),"line") ;
err += lua_pcall(L,0,0,0);
int s = lua_gettop(L);
if(err){
fprintf(stderr,"%s",lua_tostring(L,-1));
lua_pop(L,1);
}

//close
lua_close(L);

}
//////////////////////////////////////////////////////////////////////////
void test_c_call_lua_fun_withParam()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
if (luaL_loadfile(L, "luafile2.lua") || lua_pcall(L, 0, 0, 0))
{
error(L, "cannot run configuration file: %s",lua_tostring(L, -1));
return;
}
lua_getglobal(L, "do_lua_kk");
lua_getglobal(L, "a");
lua_getglobal(L, "do_lua_error");
lua_getglobal(L, "b");
lua_getglobal(L, "do_c_one");
lua_getglobal(L, "do_c");
lua_getglobal(L, "width");
lua_getglobal(L, "height");
// lua_getglobal(L, "do_c_two");
stackDump(L); //打印结果:function `lua_str_a' function `lua_str_b' function function 999 300
int k = 100;

k = lua_pcall(L, 2, 1, 1);
stackDump(L); //打印结果:function `lua_str_a' function `lua_str_b' function 8888
/*lua 执行栈上最上面的函数,使用栈上2个参数,向栈压入3个返回值
使用栈上第1位置的函数do_lua_kk作为错误处理回调函数,输出:
-------->do_c
999--add--300-->--2222
*/
k = lua_pcall(L, 1, 0, 0);
stackDump(L);

lua_close(L);
}
//////////////////////////////////////////////////////////////////////////
void test_c_call_lua_fun_withParam2()
{
lua_State* L = luaL_newstate();

//luaL_dostring 等同于luaL_loadstring() || lua_pcall()
//注意:在能够调用Lua函数之前必须执行Lua脚本,否则在后面实际调用Lua函数时会报错,
//错误信息为:"attempt to call a nil value."
const char* lua_function_code = "function add(x,y) return x + y end";
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);
lua_close(L);

}
//////////////////////////////////////////////////////////////////////////
void test_c_use_lua_variant()
{
const char* luascript = "width=111 ; height=222";
lua_State* L = luaL_newstate();
int w,h;
//luaL_loadfile的作用是编译lua文件为一个chunk
//把这个chunk当作一个匿名函数压在栈上
//lua_pcall的作用是执行这个匿名函数,然后才能取得栈上的值
if(luaL_loadstring(L,luascript) || 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 must be number\n");
return;
}
if(!lua_isnumber(L,-1)){
printf("height must be number\n");
return ;
}
w = lua_tointeger(L,-2);
h = lua_tointeger(L,-1);

printf("width = %d height = %d\n",w,h);
lua_close(L);
}
//////////////////////////////////////////////////////////////////////////
void test_c_use_lua_table()
{
lua_State* L = luaL_newstate();
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;
}
//下面取栈上的table内容
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);//入栈,栈顶位置-1的值是0.4
lua_setfield(L,-2,"b");//设置background["b"]=0.4,注意-2这个位置表示table的位置!!
lua_getfield(L,-1,"b");//取table值
stackDump(L);
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);
stackDump(L);
lua_pop(L,1); //栈被清空了

lua_close(L);
}
//////////////////////////////////////////////////////////////////////////
void test_c_new_lua_table()
{
lua_State* L = luaL_newstate();
lua_newtable(L);//Lua会生成一个新的table对象并将其压入栈中。
lua_pushnumber(L,0.3);
stackDump(L);//table 0.3
lua_setfield(L,-2,"r");//设置table["r"]=0.3完了把0.3弹出
stackDump(L);//table

lua_pushnumber(L,0.1);
lua_setfield(L,-2,"g");

lua_pushnumber(L,0.4);
lua_setfield(L,-2,"b");

stackDump(L);//table
lua_setglobal(L,"background");//栈顶元素出栈
stackDump(L);//nil
//调用该宏后,Lua会将当前栈顶的值赋值给第二个参数指定的全局变量名。
//该宏在执行成功后,会将刚刚赋值的值从栈顶弹出。

lua_getglobal(L,"background");//把background压栈
stackDump(L);//table
if (!lua_istable(L,-1)) {
printf("'background' is not a table.\n" );
return;
}
lua_getfield(L,-1,"r");//table["r"]压栈
stackDump(L);//table 0.3
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);//table

lua_getfield(L,-1,"g");//table 0.1
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);//table

lua_getfield(L,-1,"b");//table 0.4
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);//table
lua_pop(L,1);//nil

lua_close(L);
}
//////////////////////////////////////////////////////////////////////////
void test_lua_call_c_fun()
{
const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";
lua_State* L = luaL_newstate();
luaL_openlibs(L);
//将指定的函数注册为Lua的全局函数变量,其中第一个字符串参数为Lua代码在调用C函数时使用的全局函数名
//,第二个参数为实际C函数的指针。
lua_register(L, "add2", add2);
lua_register(L, "sub2", sub2);
//在注册完所有的C函数之后,即可在Lua的代码块中使用这些已经注册的C函数了。
if (luaL_dostring(L,testfunc))
printf("Failed to invoke.\n");
lua_close(L);
}
//////////////////////////////////////////////////////////////////////////
//lua文件里的print被C调用时,是可以打印到终端的!!!
void test_lua_call_c_dll_fun()
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
if(luaL_dofile(L,"lua_call_c.lua"))
printf("load lua_call_c.lua failed\n");;
lua_close(L);
}

#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}
};

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_newlib(L,arraylib_m);
//这里只注册的工厂方法。
luaL_newlib(L,arraylib_f);
return 1;
}
int main()
{
test_c_call_lua_fun_noParam();
test_c_call_lua_fun_withParam();
test_c_call_lua_fun_withParam2();
test_c_use_lua_variant();
test_c_use_lua_table();
test_c_new_lua_table();
test_lua_call_c_fun();
test_lua_call_c_dll_fun();
getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: