Lua学习笔记--Lua调用C初探

上次学习了怎么用C调用Lua的函数,并返回一个结果,这次看看怎么反过来,用Lua调用C的函数。

一.简介

C调用Lua函数比较简单,只需要操作相关的栈就可以了,但是Lua调用C的话,稍微有一点麻烦,虽然还是用栈来进行数据的传递,但是由于Lua中本身没有C中写的函数,所以需要多一步将C函数注册到Lua中的步骤。

Lua反过来调用C函数的话,首先,我们要写一个要被调用的函数,这个函数有一个格式的要求 ,返回值为int,但是这个int并不代表Lua函数的返回值,而是函数返回值的个数,Lua支持多重返回值,所以,在C函数中也需要支持多重返回值,但这个并不是通过return实现,而是通过将返回值压入那个万能的栈,然后返回返回值的个数。

函数原型如下:

//返回结果的个数,结果存在栈中
int 函数名(lua_State* L)

在写好函数之后,还需要将这个函数注册给Lua,否则Lua不知道这个函数。注册使用lua_register这个函数,需要给出这个函数在Lua中的函数名以及在C中的函数指针。函数原型如下:

//将C函数注册到Lua中(L, Lua中函数名,函数指针)
	lua_register(L, "函数名", 对应C中的函数指针);

看一个例子:

Lua程序:

--调用C的函数

print(addFunc(1, 2, 3))

C++程序:

// LuaTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>

//因为Lua是C的函数,而我们的程序是C++的,所以要使用extern "C"引入头文件
extern "C"{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "luaconf.h"
}

//Lua要调用的函数(求几个数的和),注意返回值并不是结果,而是结果的个数,Lua支持多个返回值,所以就是栈中有几个返回的值。
int addFunc(lua_State* L)
{
	double sum = 0;
	for (int i = 1; i <= lua_gettop(L); i++)
	{
		if (!lua_isnumber(L, i))
		{
			lua_pushstring(L, "argument error!");
			lua_error(L);
		}
		sum += lua_tonumber(L, i);
	}
	//将结果压入栈中
	lua_pushnumber(L, sum);
	//返回结果的个数!!!
	return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{
	//打开lua
	lua_State* L = luaL_newstate();
	//加载lib文件
	luaL_openlibs(L);

	//将刚才编写的C函数注册到Lua中(L, Lua中函数名,函数指针)
	lua_register(L, "addFunc", addFunc);

	//执行Lua文件
	luaL_dofile(L, "test.lua");

	//结束
	lua_close(L);

	system("pause");

	return 0;
}

结果:

6.0

请按任意键继续. . .

其实这样调用还是比较简单的。做完编写函数和注册函数之后,Lua中就有了这个函数,我们就可以在Lua中类似库函数那样使用这个函数了。简单起见,直接dofile了一下,执行Lua文件,调用C中的函数,并将结果在Lua中打印。

要说明的是,当注册的C/C++被Lua调用时,这个C函数享有一个独有的stack,这个栈不是共有的。这个栈在进入函数体时生成,从里面索引1到n,分别放着从Lua程序中传递过来的1到n个参数,这些函数只能看到自己的栈,看不到其他栈。

二.Lua与C交互

上面的例子仅仅是C向Lua注册了个函数,Lua使用了这个函数,最后还是通过dofile整体执行的Lua文件,并没有体现到交互。下面的例子还是上面的那个函数,不过,这次只在Lua中执行一下,结果保存在Lua中的全局变量中,再使用C函数提取这个结果,在C中打印出来。这样就体现出C和Lua交互的功能。

Lua程序:

--调用C的函数,结果保存在result全局变量中,等待C提取

result = addFunc(1, 2, 3)

C++ 程序:

// LuaTest.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>

//因为Lua是C的函数,而我们的程序是C++的,所以要使用extern "C"引入头文件
extern "C"{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "luaconf.h"
}

//Lua要调用的函数(求几个数的和),注意返回值并不是结果,而是结果的个数,Lua支持多个返回值,所以就是栈中有几个返回的值。
int addFunc(lua_State* L)
{
	double sum = 0;
	for (int i = 1; i <= lua_gettop(L); i++)
	{
		if (!lua_isnumber(L, i))
		{
			lua_pushstring(L, "argument error!");
			lua_error(L);
		}
		sum += lua_tonumber(L, i);
	}
	//将结果压入栈中
	lua_pushnumber(L, sum);
	//返回结果的个数!!!
	return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{
	//打开lua
	lua_State* L = luaL_newstate();
	//加载lib文件
	luaL_openlibs(L);

	//将刚才编写的C函数注册到Lua中(L, Lua中函数名,函数指针)
	lua_register(L, "addFunc", addFunc);

	//执行Lua文件
	luaL_dofile(L, "test.lua");

	//Lua中返回的结果在全局变量result中,将其提取出来
	lua_getglobal(L, "result");
	if (!lua_isnumber(L, -1))
		printf("result is not number!\n");

	//在C中获得结果并打印
	printf("result is %g\n", lua_tonumber(L, -1));

	//结束
	lua_close(L);

	system("pause");

	return 0;
}

结果:

result is 6

请按任意键继续. . .

当然,这个暂时只是一个互相调用的小例子,真正调用时需要做的可能会更加复杂,比如函数注册,包装等等。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 22:00:25

Lua学习笔记--Lua调用C初探的相关文章

Lua学习笔记--C调用Lua

Lua是一种嵌入式语言,可以很好的嵌入其他应用程序.lua为我们提供了一组灵活的C API,使C代码能够很好的与Lua进行交互.包括读写Lua全局变量,调用Lua函数,运行Lua代码,注册C函数反过来供Lua调用.简单的说,C能调用Lua,反过来Lua也能调用C.真的是灰常强大灵活的脚本!!现在,先来学习一下怎么用C调用Lua. 其实最简单的我们已经做过了,通过一个dofile,运行一个lua脚本文件. 一.栈 Lua与C的交互是通过一个虚拟栈进行的,这个栈对于Lua来说是严格的LIFO(后进先

lua学习笔记(2)-常用调用

assert(loadstring("math.max(7,8,9)"))dofile("scripts/xxx.lua")math.floor()math.random()   math.random(10, 100)math.min(3,4,5) math.max(2,3,4)num = tonumber(str)str = tostring(num)len = string.len(str)str = string.sbu (str, start_positi

Lua学习笔记(七):迭代器与泛型for

1.迭代器与闭包 迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素.在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素. 迭代器需要保留上一次成功调用的状态和下一次成功调用的状态,也就是他知道来自于哪里和将要前往哪里.闭包提供的机制可以很容易实现这个任务.记住:闭包是一个内部函数,它可以访问一个或者多个外部函数的外部局部变量.每次闭包的成功调用后这些外部局部变量都保存他们的值(状态).当然如果要创建一个闭包必须要创建其外部局部变量.所以一个典型的闭包的结构包含

Lua学习笔记(三):表的构造

构造器是创建和初始化表的表达式.表是Lua特有的功能强大的东西.最简单的构造函数是{},用来创建一个空表.可以直接初始化数组: 1 days = {"Sunday", "Monday", "Tuesday", "Wednesday", 2 "Thursday", "Friday", "Saturday"} Lua将“Sunday”初始化days[1](第一个元素索引为

lua学习笔记之基本语法

Lua学习笔记之基本语法 1.  赋值语句 赋值是改变一个变量的值和改变表域的最基本的方法. a = "hello".."world" t.n = t.n+1 lua可以对多个变量同时赋值,变量列表和值列表的各个元素用逗号分开,赋值语句右边的值会一次赋给左边的变量. a,b = 10,2*x    <-->a = 10;b = 2*x 遇到赋值语句lua会先计算右边所有的值然后再执行赋值操纵,所以我们可以这样进行交换变量的值: x,y = y,x    

lua学习笔记之函数

Lua学习笔记之函数 1.  函数的作用 函数主要完成指定的任务,这样的情况下函数作为调用语句使用,函数可以计算并返回值,这样的情况下函数作为赋值语句的表达式使用. 语法: funcationfunc_name(arguments-list) Statements-list end 调用函数的时候,如果参数列表为空,必须使用()表示是函数调用. Print(8*9,9/8) a = math.sin(3) +math.cos(10) print(os.date()) 上述规则有一个例外,当函数只

lua学习笔记之类型和值

Lua学习笔记之类型和值 1.全局变量 全局变量不需要声明,给一个变量赋值后即创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil 如果需要删除一个全局变量,只需要将变量赋值为nil 2.词法约定 标识符:字母或者下划线开头的字母.下划线.数字序列,最好不要使用下划线家大写字母的标识符,因为lua的保留字也是这样的. 3.命令行方式 Lua[options][script[args]] -e:直接将命令传入lua Prompt>lua –e "print(

Lua学习笔记(八):数据结构

table是Lua中唯一的数据结构,其他语言所提供的数据结构,如:arrays.records.lists.queues.sets等,Lua都是通过table来实现,并且在Lua中table很好的实现了这些数据结构. 1.数组 在Lua中通过整数下标访问table中元素,既是数组,并且数组大小不固定,可动态增长.通常我们初始化数组时,就间接地定义了数组的大小,例如: 1 a = {} -- new array 2 for i=1, 1000 do 3 a[i] = 0 4 end 5 6 --数

Lua学习笔记4:类及集成的实现

-- Lua中类的实现 -------------------------------- 基类 ---------------------------- classBase = {x = 0,y = 0} -- x,y为类的成员变量 classBase.__index = classBase -- 这句是重定义元表的索引,必须要有 --模拟构造体,一般名称为new() function classBase:new(x,y) local self = {}     -- 初始化对象自身 setme