在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
//这是一篇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; } |
请发表评论