衔接上篇,本文分为几个内容:
1、使用VS新建一个动态链接库。
2、移植lua协议库。
3、在协议库内编写Add(加法函数)并验证,这实验用来说明lua与C如何直接进行变量交互。
4、在协议库内编写byte解析成位函数并验证,这实验用来说明lua与C如何通过数组进行交互。
5、在协议库内编写lua协议栈打印函数,方便对协议库的调试。
以下具体说明如何操作:
一、使用VS新建一个动态链接库
操作步骤1:文件----新建项目,项目名称为testlua
操作步骤2:
操作步骤3:
操作步骤4:
操作步骤5:
找到下载的解压开并复制,lua-5.1.4文件夹下,src文件夹。
操作步骤6:
复制src文件夹到新建的testlua项目根目录,并改src文件夹名为luasrc,如下图所示:
二、移植lua协议库。
操作步骤1:
添加luasrc文件夹下.c与.h文件到项目内。
操作步骤2:
修改头文件包含目录。
操作步骤3:
修改输出文件名,这个文件名要和l协议内注册的函数库名一致,这个后面会详细说明。
操作步骤4:
编译一次,会出现以下错误,解决方案是移除luac.c文件。
操作步骤5:
再次编译一次,出现生成成功提示,没有错误报警,就已经移植成功了。
三、在协议库内编写Add(加法函数)并验证,这实验用来说明lua与C如何直接进行变量交互
操作步骤1:
添加以下代码到main.cpp文件内,并编译。
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
};
#include <iostream>
using namespace std;
//定义加法函数
extern "C" int Add(lua_State* L)
{
double op1 = luaL_checknumber(L,1); //取出lua调用Add函数时传递的第一个参数
double op2 = luaL_checknumber(L,2); //取出lua调用Add函数时传递的第二个参数
lua_pushnumber(L,op1+op2); //把结果压入lua栈
return 1; //返回结果
}
static luaL_Reg mylibs[] = //把Add函数注册
{
{"Add", Add},
{NULL, NULL}
};
extern "C" __declspec(dllexport)
int luaopen_mylib(lua_State* L) //注意“luaopen_mylib”函数名内的“mylib”,要与输出的文件名一致
{
const char* libName = "mylib";//注意"mylib",要与输出的文件名一致
luaL_register(L,libName,mylibs);
return 1;
}
操作步骤2:
复制生成的mylib.dll文件到C:\Program Files (x86)\Lua\5.1\clibs目录下(本例lua默认路径安装,如果安装到其他路径,放入clibs文件夹内即可)。
操作步3:
打开lua ,输入以下代码进行测试,测试结果为30。
require "mylib"
a=mylib.Add(10,20)
print(a)
四、在协议库内编写byte解析成位函数并验证,这实验用来说明lua与C如何通过数组进行交互。
操作步骤:
添加以下函数、编译、复制mylib.dll文件到clibs,参考上面Add函数的添加:
//定义把字节解析到位函数
extern "C" int ByteToBools(lua_State* L)
{
unsigned int i;
unsigned char j,m,n;
int a[16];
double op1 = luaL_checknumber(L,1); //取出lua调用函数时传递的第一个参数
lua_settop(L, 0); //把栈清空
lua_newtable(L); //新建一个表
j=(unsigned char)op1;
//刷新数组值
for(i=0;i<8;i++)
{
m=1;
m<<=i;
n=j & m;
if(n>0)
{
a[i]=1;
}
else
{
a[i]=0;
}
}
//把数组写入到栈
for(i=0;i<8;i++)
{
lua_pushinteger(L,a[i]); //将数组的数据入栈,此时站内从栈顶开始为a[i]、table
lua_rawseti(L,-2,i+1); //将刚刚入栈的数据设置为数组的第i+1个数据,同时这个数据会自动从栈里pop
}
return 1;
}
注意这里要改成如下所示:
static luaL_Reg mylibs[] =
{
{"Add", Add},
{"ByteToBools", ByteToBools},
{NULL, NULL}
};
输入测试代码,执行结果如下:
require "mylib"
array={}
array=mylib.ByteToBools(255)
for i=1,8 do
print(array[i])
end
五、在协议库内编写lua协议栈打印函数,方便对协议库的调试。
操作步骤1:
添加以下函数:
//打印lua栈内容
static void stackDump(lua_State* L){
cout<<"当前栈(栈顶到栈底):";
int i = 0;
int top = -lua_gettop(L);
for (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;
}
}
cout<<endl;
}
函数用法:
比如把Add函数改成这样:
//定义加法函数
extern "C" int Add(lua_State* L)
{
cout<<"第一次打印栈内内容"<<endl;
stackDump(L);
double op1 = luaL_checknumber(L,1); //取出lua调用Add函数时传递的第一个参数
cout<<"第二次打印栈内内容"<<endl;
stackDump(L);
double op2 = luaL_checknumber(L,2); //取出lua调用Add函数时传递的第二个参数
cout<<"第三次打印栈内内容"<<endl;
stackDump(L);
lua_pushnumber(L,op1+op2); //把结果压入lua栈
cout<<"第四次打印栈内内容"<<endl;
stackDump(L);
return 1; //返回结果
}
再次编译、复制mylib.dll文件到clibs,输入测试代码,执行结果如下:
require "mylib"
a=mylib.Add(10,20)
print(a)
总结:
1、以上步骤操作完成后总体代码如下:
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
};
#include <iostream>
using namespace std;
//打印lua栈内容
static void stackDump(lua_State* L){
cout<<"当前栈(栈顶到栈底):";
int i = 0;
int top = -lua_gettop(L);
for (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;
}
}
cout<<endl;
}
//定义加法函数
extern "C" int Add(lua_State* L)
{
cout<<"第一次打印栈内内容"<<endl;
stackDump(L);
double op1 = luaL_checknumber(L,1); //取出lua调用Add函数时传递的第一个参数
cout<<"第二次打印栈内内容"<<endl;
stackDump(L);
double op2 = luaL_checknumber(L,2); //取出lua调用Add函数时传递的第二个参数
cout<<"第三次打印栈内内容"<<endl;
stackDump(L);
lua_pushnumber(L,op1+op2); //把结果压入lua栈
cout<<"第四次打印栈内内容"<<endl;
stackDump(L);
return 1; //返回结果
}
//定义把字节解析到位函数
extern "C" int ByteToBools(lua_State* L)
{
unsigned int i;
unsigned char j,m,n;
int a[16];
double op1 = luaL_checknumber(L,1); //取出lua调用函数时传递的第一个参数
lua_settop(L, 0); //把栈清空
lua_newtable(L); //新建一个表
j=(unsigned char)op1;
//刷新数组值
for(i=0;i<8;i++)
{
m=1;
m<<=i;
n=j & m;
if(n>0)
{
a[i]=1;
}
else
{
a[i]=0;
}
}
//把数组写入到栈
for(i=0;i<8;i++)
{
lua_pushinteger(L,a[i]); //将数组的数据入栈,此时站内从栈顶开始为a[i]、table
lua_rawseti(L,-2,i+1); //将刚刚入栈的数据设置为数组的第i+1个数据,同时这个数据会自动从栈里pop
}
return 1;
}
static luaL_Reg mylibs[] =
{
{"Add", Add},
{"ByteToBools", ByteToBools},
{NULL, NULL}
};
extern "C" __declspec(dllexport)
int luaopen_mylib(lua_State* L) //注意“luaopen_mylib”函数名内的“mylib”,要与输出的文件名一致
{
const char* libName = "mylib";//注意"mylib",要与输出的文件名一致
luaL_register(L,libName,mylibs);
return 1;
}
2、本文详细讲解了,使用VS2010如何新建一个DLL工程,如何移植LUA协议库,协议库如何与lua进行数组交互、变量交互。
3、下节将讲解在当前基础上如何移植Snap7协议库到工程内,如何让Snap7与Lua协议库相互兼容,能顺利的编译完成,欢迎大家持续关注。