欢迎来到NiceSpace!祝大家开心每一天!
  • C++
  • lua
将C/C++注册到LUA环境中使用

刚刚学习lua,学习到如何将C/C++函数接口注册到lua环境中,使之可以在lua被调用。

在http://www.lua.org/ftp/点击打开链接处下载lua-5.1.5源码

使用C语言写一个base64编码的函数接口,函数参数为输入字符串,输入字符串长度,输出字符串长度。返回值为编码后的字符串

注册到lua的方式有两种,一种是lua解释器如果支持动态链接,使用动态链接机制,将函数接口编译成动态链接库,然后将动态链接库放到lua的C路径(LUA_CPATH)中(例如可以放在跟lua源码文件同一目录下),然后直接使用require "base64",这句话会使自己编写的动态链接库链接到lua,并寻找luaopen_base64,将模块注册到package.loaded中。另一种方式是直接将自己写好的接口函数与lua源文件一起重新编译生成一个新的lua解释器,使用新的解释器代替旧的。此外,还需要以某种方式来告诉解释器,它应在打开新状态的同时打开这个模块,最简单的做法是将luaopen_base64加到luaL_openlibs会打开的标准库列表中,这个列表在文件linit.c中。

一.使用动态链接库方式将接口注册到lua环境

源码:

 

  1. // base64.cpp : 定义 DLL 应用程序的导出函数。  
  2. //  
  3. #include <stddef.h>  
  4. #include "stdio.h"  
  5. #include "stdlib.h"  
  6. #include "string.h"  
  7.   
  8. extern "C"  
  9. {  
  10.   
  11. #include "lua.h"  
  12. #include "lauxlib.h"  
  13. #include "lualib.h"  
  14.   
  15.   
  16.   
  17. char code[65] = {  
  18.     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',  
  19.     'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',  
  20.     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',  
  21.     'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',  
  22.     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',  
  23.     'o', 'p', 'q', 'r', 's', 't', 'u', 'v',  
  24.     'w', 'x', 'y', 'z', '0', '1', '2', '3',  
  25.     '4', '5', '6', '7', '8', '9', '+', '/',  
  26.     '='  
  27. };  
  28.   
  29. char* trans(const char* str, unsigned int num)  
  30. {  
  31.     char* res = (char*)malloc(sizeof(char) * 4);  
  32.     unsigned char* s = (unsigned char*)str;  
  33.     *res = *s >> 2;  
  34.     *(res + 1) = ((*(s + 1) >> 4) + (*(s) << 4)) & 0x3f;  
  35.     *(res + 2) = ((*(s + 1) << 2) + (*(s + 2) >> 6)) & 0x3f;  
  36.     *(res + 3) = *(s + 2) & 0x3f;  
  37.     return res;  
  38. }  
  39.   
  40. char transform(char s)  
  41. {  
  42.     return code[s];  
  43. }  
  44.   
  45. char* encode(const char* str, unsigned int num, unsigned int* resnum)  
  46. {  
  47.     int numtmp = num;  
  48.     int count = 0;  
  49.     char* temp = NULL;  
  50.     char* res = NULL;  
  51.     char* point = NULL;  
  52.     int i;  
  53.     if((numtmp % 3) != 0)  
  54.         numtmp = (numtmp / 3 + 1) * 3;  
  55.     count  = (numtmp / 3) * 4;  
  56.     temp = (char*)malloc(numtmp * sizeof(char));  
  57.     res = (char*)malloc(count * sizeof(char));  
  58.     memset(temp, 0, numtmp * sizeof(char));  
  59.     memset(res, 0, count * sizeof(char));  
  60.     memcpy(temp, str, num);  
  61.     for(i = 0; i < numtmp / 3; i++)  
  62.     {  
  63.         point = trans((temp + i * 3), 3);  
  64.         memcpy((res+i*4), point, 4);  
  65.     }  
  66.     if((numtmp - num) == 1)  
  67.     {  
  68.         *(res + count - 1) = 64;  
  69.     }  
  70.     else if((numtmp - num) == 2)  
  71.     {  
  72.         *(res + count - 1) = 64;  
  73.         *(res + count - 2) = 64;  
  74.     }  
  75.     else  
  76.     {  
  77.         //none  
  78.     }  
  79.     for(i = 0; i < count; i++)  
  80.     {  
  81.         *(res + i) = transform(*(res + i));  
  82.     }  
  83.     *resnum = count;  
  84.     return res;  
  85. }  
  86.   
  87. static int lbase64(lua_State* L)  
  88. {  
  89.     const char* str = lua_tostring(L, 1);  
  90.     unsigned int num = lua_tointeger(L, 2);  
  91.     unsigned int count = 0;  
  92.   
  93.     char* res = encode(str, num, &count);  
  94.   
  95.     if(res)  
  96.     {  
  97.         lua_pushlstring(L, res, count);  
  98.         lua_pushinteger(L, count);  
  99.         return 2;  
  100.     }  
  101.     else  
  102.     {  
  103.         lua_pushnil(L);  
  104.         return 1;  
  105.     }  
  106. }  
  107.   
  108. static const struct luaL_Reg base64[] = {  
  109.     {"lbase64", lbase64},  
  110.     {NULL, NULL}  
  111. };  
  112.   
  113. __declspec(dllexport) int  luaopen_base64(lua_State* L)  
  114. {  
  115.     luaL_register(L, "base64", base64);  
  116.     return 1;  
  117. }  
  118.   
  119. }  

编译环境要包含lua源码库,然后将以上源码编译成动态链接库,放到lua源码src目录下,这样在lua中就可以调用base64接口,将输入字符串和输入字符串长度作为参数,返回输出字符串和输出字符串长度(以上base64源码写的很糙很SB,可以忽略base64的实现,主要看是如何将接口注册到lua中)。

然后可以创建一个test.lua文件,输入:

local base64= require "base64"

local input = "hello world!"

local res = mylib.lbase64(input, string.len(input))

print(res)

运行文件,输出:aGVsbG8gd29ybGQh

 

二.将编写的函数接口与lua源码一起重新编译成lua解释器

源码:

 

  1. // base64.cpp : 定义 DLL 应用程序的导出函数。  
  2. //  
  3. #include <stddef.h>  
  4. #include "stdio.h"  
  5. #include "stdlib.h"  
  6. #include "string.h"  
  7.   
  8. #define LUA_LIB  
  9.   
  10. #include "lua.h"  
  11. #include "lauxlib.h"  
  12. #include "lualib.h"  
  13.   
  14.   
  15.   
  16. char code[65] = {  
  17.     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',  
  18.     'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',  
  19.     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',  
  20.     'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',  
  21.     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',  
  22.     'o', 'p', 'q', 'r', 's', 't', 'u', 'v',  
  23.     'w', 'x', 'y', 'z', '0', '1', '2', '3',  
  24.     '4', '5', '6', '7', '8', '9', '+', '/',  
  25.     '='  
  26. };  
  27.   
  28. char* trans(const char* str, unsigned int num)  
  29. {  
  30.     char* res = (char*)malloc(sizeof(char) * 4);  
  31.     unsigned char* s = (unsigned char*)str;  
  32.     *res = *s >> 2;  
  33.     *(res + 1) = ((*(s + 1) >> 4) + (*(s) << 4)) & 0x3f;  
  34.     *(res + 2) = ((*(s + 1) << 2) + (*(s + 2) >> 6)) & 0x3f;  
  35.     *(res + 3) = *(s + 2) & 0x3f;  
  36.     return res;  
  37. }  
  38.   
  39. char transform(char s)  
  40. {  
  41.     return code[s];  
  42. }  
  43.   
  44. char* encode(const char* str, unsigned int num, unsigned int* resnum)  
  45. {  
  46.     int numtmp = num;  
  47.     int count = 0;  
  48.     char* temp = NULL;  
  49.     char* res = NULL;  
  50.     char* point = NULL;  
  51.     int i;  
  52.     if((numtmp % 3) != 0)  
  53.         numtmp = (numtmp / 3 + 1) * 3;  
  54.     count  = (numtmp / 3) * 4;  
  55.     temp = (char*)malloc(numtmp * sizeof(char));  
  56.     res = (char*)malloc(count * sizeof(char));  
  57.     memset(temp, 0, numtmp * sizeof(char));  
  58.     memset(res, 0, count * sizeof(char));  
  59.     memcpy(temp, str, num);  
  60.     for(i = 0; i < numtmp / 3; i++)  
  61.     {  
  62.         point = trans((temp + i * 3), 3);  
  63.         memcpy((res+i*4), point, 4);  
  64.     }  
  65.     if((numtmp - num) == 1)  
  66.     {  
  67.         *(res + count - 1) = 64;  
  68.     }  
  69.     else if((numtmp - num) == 2)  
  70.     {  
  71.         *(res + count - 1) = 64;  
  72.         *(res + count - 2) = 64;  
  73.     }  
  74.     else  
  75.     {  
  76.         //none  
  77.     }  
  78.     for(i = 0; i < count; i++)  
  79.     {  
  80.         *(res + i) = transform(*(res + i));  
  81.     }  
  82.     *resnum = count;  
  83.     return res;  
  84. }  
  85.   
  86. static int lbase64(lua_State* L)  
  87. {  
  88.     const char* str = lua_tostring(L, 1);  
  89.     unsigned int num = lua_tointeger(L, 2);  
  90.     unsigned int count = 0;  
  91.   
  92.     char* res = encode(str, num, &count);  
  93.   
  94.     if(res)  
  95.     {  
  96.         lua_pushlstring(L, res, count);  
  97.         lua_pushinteger(L, count);  
  98.         return 2;  
  99.     }  
  100.     else  
  101.     {  
  102.         lua_pushnil(L);  
  103.         return 1;  
  104.     }  
  105. }  
  106.   
  107. static const struct luaL_Reg base64[] = {  
  108.     {"lbase64", lbase64},  
  109.     {NULL, NULL}  
  110. };  
  111.   
  112. LUA_API int  luaopen_base64(lua_State* L)  
  113. {  
  114.     luaL_register(L, "base64", base64);  
  115.     return 1;  
  116. }  

将写好的接口保存文件为lbase.c(此命名是有目的的,下面说)

 

在lua源文件linit.c中的luaL_openlibs中加入自己的luaopen_base64。

在lua源文件lualib.h中声明自己的luaopen_base64

这里可能看到上面的源码中luaopen_base64前有个LUA_API,并且在文件的开头有个宏定义#define LUA_LIB,这里在文件头部声明宏定义LUA_LIB表示这个模块是一个lua的函数库,因此下面的LUA_API表示是用来导出的。这里可以看下lua源文件luaconf.h文件找到关于这两个宏的解释。

最后使用与源码一同下载下来的编译脚本进行编译,编译脚本内容如下(脚本路径:lua-5.1.5\etc\luavs.bat):

 

  1. @rem Script to build Lua under "Visual Studio .NET Command Prompt".  
  2. @rem Do not run from this directory; run it from the toplevel: etc\luavs.bat .  
  3. @rem It creates lua51.dll, lua51.lib, lua.exe, and luac.exe in src.  
  4. @rem (contributed by David Manura and Mike Pall)  
  5.   
  6. @setlocal  
  7. @set MYCOMPILE=cl /nologo /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE  
  8. @set MYLINK=link /nologo  
  9. @set MYMT=mt /nologo  
  10.   
  11. cd src  
  12. %MYCOMPILE% /DLUA_BUILD_AS_DLL l*.c
  13. del lua.obj luac.obj  
  14. %MYLINK% /DLL /out:lua51.dll l*.obj  
  15. if exist lua51.dll.manifest^  
  16.   %MYMT% -manifest lua51.dll.manifest -outputresource:lua51.dll;2  
  17. %MYCOMPILE% /DLUA_BUILD_AS_DLL lua.c  
  18. %MYLINK% /out:lua.exe lua.obj lua51.lib  
  19. if exist lua.exe.manifest^  
  20.   %MYMT% -manifest lua.exe.manifest -outputresource:lua.exe  
  21. %MYCOMPILE% l*.c print.c  
  22. del lua.obj linit.obj lbaselib.obj ldblib.obj liolib.obj lmathlib.obj^  
  23.     loslib.obj ltablib.obj lstrlib.obj loadlib.obj  
  24. %MYLINK% /out:luac.exe *.obj  
  25. if exist luac.exe.manifest^  
  26.   %MYMT% -manifest luac.exe.manifest -outputresource:luac.exe  
  27. del *.obj *.manifest  
  28. cd ..  

脚本会创建lua.dll,lua.lia,lua解释器,lua编译器。

 

看到红色标记的地方,是编译src文件中所有l开头的文件,这也是上面说将写好的文件命名为lbase.c,这样就不需要改动脚本内容直接编译进去了。

然后可以创建一个test.lua文件,输入:

local base64= require "base64"

local input = "hello world!"

local res = base64.lbase64(input, string.len(input))

print(res)

运行文件,输出:aGVsbG8gd29ybGQh

随机文章
3D图形学总结(六)—背面消除与物体剔除 常用排序算法总结 3D图形学总结(十二)—纹理滤波 3D图形学总结(十一)—深度缓存 四元数的一些整理
推荐文章