本篇仅简单介绍使用lua_tinker让lua调用C++函数的过程, C++调用lua函数可以参见博客Lua脚本和C++交互(一).

未完待续.

(一) lua调用C++全局函数

这里以lua_tinker自带的sample1作为分析例子.C++源码如下:

// sample1.cpp
#include "stdafx.h"
#include "../lua_tinker/lua_tinker.h"int cpp_func(int arg1, int arg2)
{return arg1 + arg2;
}int _tmain(int argc, _TCHAR* argv[])
{    lua_State* L = lua_open();luaopen_base(L);lua_tinker::def(L, "cpp_func", cpp_func);lua_tinker::dofile(L, "sample1.lua");int result = lua_tinker::call<int>(L, "lua_func", 3, 4);printf("lua_func(3,4) = %d\n", result);lua_close(L);return 0;
}

lua文件源码如下:

-- sample1.lua
result = cpp_func(1, 2)print("cpp_func(1,2) = "..result)function lua_func(arg1, arg2)return arg1 + arg2
end

从main函数开始分析. 首先通过lua_open获取lua栈对象,再打开lua库(luaopen_base). 接下来,lua_tinker::def注册一个C++全局函数,lua_tinker::dofile打开lua文件,通过lua_tinker::call调用到sample1.lua里面的lua函数.最后关闭释放lua栈对象(lua_close).本文重点在于探究ua_tinker::def如何完成C++全局函数的注册.

(1) lua_tinker只有一个.h和.cpp文件,在lua_tinker.h里面,我们找到了上面的函数调用,如下:

// global function
// lua_tinker::def(L, "cpp_func", cpp_func);
template<typename F>
void def(lua_State* L, const char* name, F func)
{ lua_pushstring(L, name);lua_pushlightuserdata(L, func);push_functor(L, func);lua_settable(L, LUA_GLOBALSINDEX);
}

在代码中,我们可以看到,首先将全局函数名称"cpp_func"压入lua栈(), 此时的lua栈只有这一个元素且为栈顶, 然后我们再将全局函数对应的函数指针压入栈(查lua_reference可以知道,如果是light userdata(而不是full userdata)的话,lua_pushlightuserdata只是简单地压入函数指针), 此时的lua栈有两个元素,栈顶为func函数指针,第2个元素是我们刚才压入的全局函数名称;第3步的push_functor是lua_tinker对压入cclosure(c闭包)函数lua_pushcclosure的一个封装,查看此函数:

template<typename RVal, typename T1, typename T2>
void push_functor(lua_State *L, RVal (*func)(T1,T2))
{ lua_pushcclosure(L, functor<T1,T2>::invoke<RVal>, 1);
}

这里涉及到模板函数的重载,模板相关知识参见系列博客C++ template —— 模板基础(一).这里不做过多阐述.

上面我们的全局函数cpp_func是一个接受两个参数且有一个返回值的函数,所以我们找到了如上的模板函数, 从代码中可以看到,push_functor()只是简单地调用lua函数lua_pushcclosure,但是对参数做了一层封装.lua_pushcclosure接受三个参数,第2个参数表示要压入的c闭包函数体(此处为functor结构体的invoke函数),第3个参数表示此c闭包关联的upvalue个数(最大255).本例中只有一个(会获取到上面通过lua_pushlightuserdata压入的函数指针), lua_pushcclosure压入c闭包,同时会把所有的upvalue(这里只有函数指针)全都pop出栈.此时的lua栈只有两个元素,栈顶也就是刚刚压入的cclosure,下面一个元素是函数名称. 接下来,我们再看看functor如何封装此函数指针:

template<typename T1, typename T2>
struct functor<T1,T2>
{template<typename RVal>static int invoke(lua_State *L) { push(L,upvalue_<RVal(*)(T1,T2)>(L)(read<T1>(L,1),read<T2>(L,2))); return 1; }template<>static int invoke<void>(lua_State *L) { upvalue_<void(*)(T1,T2)>(L)(read<T1>(L,1),read<T2>(L,2)); return 0; }
};

这里涉及到的是类(结构体)模板和类模板偏特化的内容,这里也不做过多阐述,感兴趣同样可以参见上面模板系列博客.

根据类模板偏特化,我们找到了上面接收两个模板参数的对应functor代码,可以看到,invoke执行的操作就是将全局函数压入栈. upvalue_获取闭包的upvalue,这里是全局函数cpp_func的指针,再通过read指定(cpp_func全局函数所需要的)两个参数,最后通过push压入lua栈.upvalue_代码如下:

// get value from cclosure
template<typename T>
T upvalue_(lua_State *L)
{return user2type<T>::invoke(L, lua_upvalueindex(1));
}

lua_upvalueindex(1)获取cclosure中的第1个upvalue,也即全局函数地址.

最后,通过lua_settable(L, LUA_GLOBALSINDEX);找到全局表索引位置的全局表t,并以栈顶为value(cclosure),下一个元素为key(全局函数名称),设置t[key] = value;将封装过的元素函数指针设置进lua全局表里面,这样,在lua文件sample1.lua中,就可以直接通过全局函数名称"cpp_func"调用到C++的函数了.

本篇博文为个人分析,如发现错误,请留言指出,共同进步,谢谢!

(二) lua调用C++ 的非全局函数

[参考]:lua 函数调用1 -- 闭包详解和C调用

转载于:https://www.cnblogs.com/yyxt/p/5503449.html

lua_tinker源码笔记1相关推荐

  1. angularjs源码笔记(3)--injector

    2019独角兽企业重金招聘Python工程师标准>>> 简介 injector是用来做参数自动注入的,例如 function fn ($http, $scope, aService) ...

  2. spring aop原理_Spring知识点总结!已整理成142页离线文档(源码笔记+思维导图)...

    写在前面 由于Spring家族的东西很多,一次性写完也不太现实.所以这一次先更新Spring[最核心]的知识点:AOP和IOC 无论是入门还是面试,理解AOP和IOC都是非常重要的.在面试的时候,我没 ...

  3. 数据结构源码笔记(C语言描述)汇总

    数据结构源码笔记(C语言):英文单词按字典序排序的基数排序 数据结构源码笔记(C语言):直接插入排序 数据结构源码笔记(C语言):直接选择排序 数据结构源码笔记(C语言):置换-选择算法 数据结构源码 ...

  4. 数据结构源码笔记(C语言):英文单词按字典序排序的基数排序

    //实现英文单词按字典序排序的基数排序算法#include<stdio.h> #include<malloc.h> #include<string.h>#defin ...

  5. 数据结构源码笔记(C语言):索引文件建立和查找

    //实现索引文件建立和查找算法#include<stdio.h> #include<malloc.h> #include<string.h> #include< ...

  6. 数据结构源码笔记(C语言):快速排序

    //实现快速排序算法 #include<stdio.h> #include<malloc.h> #define MAXE 20typedef int KeyType; type ...

  7. 数据结构源码笔记(C语言):冒泡排序

    //冒泡排序算法实现 #include<stdio.h> #include<malloc.h> #define MAXE 20typedef int KeyType; type ...

  8. 数据结构源码笔记(C语言):希尔插入排序

    //实现希尔插入排序算法 #include<stdio.h> #include<malloc.h> #define MAXE 20typedef int KeyType; ty ...

  9. 数据结构源码笔记(C语言):直接插入排序

    //实现直接插入排序算法#include<stdio.h> #include<malloc.h> #define MAXE 20typedef int KeyType; typ ...

最新文章

  1. R语言使用ggplot2包使用geom_violin函数绘制分组小提琴图(配置边界颜色)实战
  2. 使用三防漆来保护PCB的敷铜面
  3. c语言boolean作为全局变量_最容易忽略的C语言知识点细节,编程大牛进阶之路!...
  4. JZ2440学习总结3
  5. 【Linux】一步一步学Linux——consoletype命令(247)
  6. 上传项目到gitHub,上传报错和删除gitHub上的项目
  7. 将字符串String str= “abc god 中国 java“ 反转每个单词 结果: “cba dog 国中
  8. mysql 中float存入int数据显示失真问题
  9. 计算机断电无法启动不了系统,电脑因为强制断电导致系统无法正常启动的解决办法...
  10. unity不规则点击_【Unity游戏开发】UGUI不规则区域点击的实现
  11. AppCan西游汇“移动互联网创业者技术沙龙” (重庆站)
  12. 谷歌学术上不了的解决办法
  13. 科学解释超级计算机,人工智能、现代科学证明:宇宙是虚拟的,真实世界是超级计算机...
  14. redis常用命令 (查询出所有的商品,并返回json给客户端)redis之路(八)
  15. asp.net获取URL和IP地址
  16. Numpy数据处理基础方法:运算、随机排列、修改
  17. VCC、VDD、VSS
  18. H5中 JS 禁用安卓手机物理返回键 , 微信浏览器中也支持
  19. Office frontpage 2003 SKU017.CAB
  20. outlook插入附件就闪退

热门文章

  1. RTX5 | 线程管理04 - 线程加入osThreadJoin
  2. Java笔记-编码方式创建kaptcha验证码
  3. Linux工作笔记-配置.bashrc或.cshrc使core文件产生(方便gdb调试)
  4. 设计模式工作笔记-简单工厂场景与实现(针对接口编程的设计思想)
  5. Qt工作笔记-QDialog模式对话框传递数据给主窗口
  6. basic认证 接口 php,PHP 模拟 HTTP 基本认证(Basic Authentication) - 黄棣-dee - 博客园...
  7. 2013计算机系统导论,计算机系统导论2013期末(20页)-原创力文档
  8. 安远职业高中计算机专业,安远中等专业学校2021年招生简章
  9. springboot 物联网_Confluent Kafka,KSQL,Spring Boot和分布式SQL开发物联网实战
  10. 面试篇------性能测试+调优