Lua 与 C 的交互

lua源码解析三,lua_cpcall等一系列函数调用过程中的封装步骤各有什么作用 在追踪lua源码过程中,有一堆的关于call的函数,令人眼花缭乱,如果不稍作整理,就很难掌握什么情况下调用哪个call函数,以下是列举的几个call相关函数 type void (*Pfunc)(lua_State*L, void* ud); void (lua_call)(lua_State*L, int nargs, int nresults); int (lua_pcall)(lua_... 阅读详情

转载:https://www.cnblogs.com/chenny7/p/3993456.html

Lua是一个嵌入式的语言,它不仅可以是一个独立运行的程序,也可以是一个用来嵌入其它应用的程序库。

C API是一个C代码与Lua进行交互的函数集,它由以下几部分构成:

1、  读写Lua全局变量的函数;

2、  调用Lua函数的函数;

3、  运行Lua代码片段的函数;

4、  注册C函数后可以在Lua中被调用的函数;

 

在C和LUA之间交互的关键在于一个虚拟栈(virtual stack),数据交互通过栈进行。操作数据时,首先将数据拷贝到栈上,然后获取数据,栈中的每个数据通过索引值进行定位,索引值为正时表示相对于栈底的偏移索引,索引值为负时表示相对于栈顶的偏移索引。索引值以1或 -1起始值,因此栈顶索引值永远为-1, 栈底索引值永远为1 。 "栈"相当于数据在Lua和C之间的中转地,每种数据都有相应的存取接口 。

另外,还可以使用栈来保存临时变量。栈的使用解决了C和LUA之间两个不协调的问题:

1、  Lua使用自动垃圾收集机制,而C要求显式的分配和释放内存;

2、  Lua使用动态数据类型,而C使用静态类型;

 

特别注意的是:

1、每当Lua调用C函数时,C函数会使用一个局部栈,这个局部栈与之前的栈,以及其它正在调用的C函数使用的栈都是相互独立的。Lua和C就使用这个局部的栈进行数据交互。

2、当Lua调用C时,栈至少包含LUA_MINSTACK(20)个位置,程序员也可以使用lua_checkstack函数来增加栈的大小。

3、使用伪索引(Pseudo-Indices)来表示一些不在栈中的数据,比如thread环境、C函数环境、registry、C闭包的upvalues。

  • thread环境(全局变量也在这里),使用伪索引 LUA_GLOBALSINDEX;
  • 运行中的C函数环境,使用伪索引 LUA_ENVIRONINDEX;
  • Registry,使用伪索引 LUA_REGISTRYINDEX;
  • C闭包的upvalues,可以使用lua_upvalueindex(n)来访问第n个upvalue;

 

关于Registry:

在C里面如果函数要保存持久状态,只能依靠全局或static变量,但这样C API库就无法为多个LuaState状态同时提供服务(就类似于带有static变量的C函数是不可重入的)。为此Lua提供了一个名为Registry的预定义table,允许C API往Registry里面存储数据。

 

关于References:

Reference其实就是在一个指定的表t中保存一次lua的数据对象,Refenence本身其实就是表t的索引子,简称RefIndex,当RefIndex作为Refenence时,t[RefIndex]其实就是用户要求引用的lua数据对象。当RefIndex被luaL_unref()回收时,t每一个被回收的RefIndex构成一个单向链表: t[Refindex] = Refindex0, t[Refindex0] = Refindex1, t[Refindex1] = Refindex2 ... t[0] = Refindex。

 

注意,t[0]始终是指向了空闲链表的头部。每次调用luaL_ref()且回收链表为空时,都会产生一个新的Reference,每次调用luaL_unref()都会销毁一个指定的Reference存入空闲链表中。

 

 

 


C API接口 

 

类型声明

typedef double lua_Number;
typedef ptrdiff_t lua_Integer;

 

初始化lua状态机

lua_State* lua_open();

lua_State *lua_newstate (lua_Alloc f, void *ud);

lua_newstate 创建一个新的、独立的Lua状态机,如果因为内存不足导致创建失败,返回NULL。参数f 指定内存分配函数,参数ud是传给f 函数的指针。

lua_open 没有指定内存分配函数的功能,不建议再使用。

注意:lua_State表示的一个Lua程序的执行状态,它代表一个新的线程(注意是指Lua中的thread类型,不是指操作系统中的线程),每个thread拥有独立的数据栈以及函数调用链,还有独立的调试钩子和错误处理方法。

 

销毁lua状态机

void lua_close(lua_State *L);

销毁Lua状态机的所有对象,回收分配的内存。

 

加载lua库

void luaL_openlibs(lua_State *L);                   

void luaopen_base(lua_State *L);

void luaopen_package(lua_State *L);

void luaopen_string(lua_State *L);

void luaopen_io(lua_State *L);

void luaopen_table(lua_State *L);

void luaopen_math(lua_State *L);

luaL_openlibs 在给定的Lua状态机中打开所有的标准Lua库;

 

编译/加载 lua代码

int luaL_dofile(lua_State *L, char *lua_script);

int luaL_dostring (lua_State *L, const char *str);

int lua_load (lua_State *L, lua_Reader reader, void *data,const char *chunkname);

int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, const char *name);

int luaL_loadfile (lua_State *L, const char *filename);

int luaL_loadstring (lua_State *L, const char *s);

luaL_dofile 加载并执行给定lua文件,成功返回0,错误返回1;

luaL_dostring 加载并执行给定string,成功返回0,错误返回1;

lua_load 加载一段chunk(但并不执行它),并将编译后的代码作为一个函数压入堆栈,如果发生错误,则将错误消息压入堆栈;

luaL_loadbuffer 从一个buffer中加载chunk;

luaL_loadfile从文件加载chunk;

luaL_loadstring从字符串加载chunk;

 

函数参数检查

void luaL_checkany (lua_State *L, int narg);
int luaL_checkint (lua_State *L, int narg);
lua_Integer luaL_checkinteger (lua_State *L, int narg);
long luaL_checklong (lua_State *L, int narg);
const char *luaL_checklstring (lua_State *L, int narg, size_t *l);
lua_Number luaL_checknumber (lua_State *L, int narg);
int luaL_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]);
const char *luaL_checkstring (lua_State *L, int narg);
void luaL_checktype (lua_State *L, int narg, int t);
void *luaL_checkudata (lua_State *L, int narg, const char *tname);

luaL_checkany 检查函数有多少个(由narg指定)参数;

luaL_checktype 检查函数第narg个参数是否为指定类型;

luaL_checkudata 检查函数第narg个参数是否为name类型的userdata;
luaL_checkint/luaL_checkinterger 等接口非常类似:

以luaL_checkint为例,它是检查函数的第narg个参数类型是否number型,并且返回这个number型参数;

luaL_checkoption 检查函数第narg个参数是否位字符串类型,并且在lst[](字符串数组)中搜索这个字符串,最后返回匹配的数组下标,如未能匹配,引发一个错误。如果参数def非空,当narg参数不存在或为nil时,就是要def作为搜索串。这个函数的作用是将字符串映射为C的enum类型。

 

 

table操作 

void lua_createtable (lua_State *L, int narr, int nrec);

void lua_newtable (lua_State *L);
void lua_settable (lua_State *L, int index);
void lua_gettable (lua_State *L, int index);

lua_createtable 创建一个空table并压入堆栈,它会为narr个数组风格元素,和nrec个记录风格元素预分配内存空间。

lua_newtable 创建一个空table,并压入stack,等价于 lua_createtable(L, 0, 0);
lua_settable 相当于t[k]=v 操作,其中值t由参数index指定,v是栈顶,k是栈顶下一个元素;这个函数会将key和value都弹出栈;

lua_gettable 将t[k]压入堆栈,由参数index指定操作的table,k是栈顶元素。这个函数会弹出栈顶的key,并由t[k]代替;
 

 

metatable操作

int luaL_newmetatable (lua_State *L, const char *tname);

void luaL_getmetatable (lua_State *L, const char *tname);

int lua_getmetatable (lua_State *L, int index);

int lua_setmetatable (lua_State *L, int index);

int luaL_getmetafield (lua_State *L, int obj, const char *e);

luaL_newmetatable 在Registry中创建一个key为tname的metatable,并返回1;如果Registry 已经有tname这个key,则返回0;这两种情况都会将metatable压入堆栈;

luaL_getmetatable 将Registry中key为tname的metatable压入堆栈;

luaL_getmetatable 将index处的元表压入堆栈;

lua_setmetatable 弹出栈顶,并将它作为由index指定元素的元表;

luaL_getmetafield 将索引obj处的元素的元表的e字段压入堆栈;

 

 

stack操作

void lua_pushboolean (lua_State *L, int b);
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
void lua_pushcfunction (lua_State *L, lua_CFunction f);
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
void lua_pushinteger (lua_State *L, lua_Integer n);
void lua_pushlightuserdata (lua_State *L, void *p);
void lua_pushliteral (lua_State *L, const char *s);
void lua_pushlstring (lua_State *L, const char *s, size_t len);
void lua_pushnil (lua_State *L);
void lua_pushstring (lua_State *L, const char *s);

lua_pushfstring 将一个格式化字符串压入堆栈,并返回指向这个字符串的指针;

lua_pushlstring 将一个指定大小的字符串压入堆栈;

lua_pushvalue 将栈中指定索引的元素复制一份到栈顶;

值得注意的是,向栈中压入一个元素时,应该确保栈中具有足够的空间,可以调用lua_checkstack来检测是否有足够的空间。

实质上这些API是把C语言里面的值封装成Lua类型的值压入栈中的,对于那些需要垃圾回收的元素(如string、full userdata),在压入栈时,都会在Lua(也就是Lua虚拟机中)生成一个副本,从此不会再依赖于原来的C值。例如lua_pushstring 向栈中压入一个以'\0'结尾的字符串,在C中调用这个函数后,可以任意修改或释放这个字符串,也不会出现问题。

 

void lua_pop(lua_State *L, int n);

int lua_gettop (lua_State *L);

void lua_concat (lua_State *L, int n);

void lua_getfield (lua_State *L, int index, const char *k);

void lua_setfield (lua_State *L, int index, const char *k);

void lua_getglobal(lua_State *L, char *name);

void lua_setglobal (lua_State *L, const char *name);

void lua_insert (lua_State *L, int index);

void lua_remove (lua_State *L, int index);

void lua_replace (lua_State *L, int index);

int lua_next (lua_State *L, int index);

size_t lua_objlen (lua_State *L, int index);

void luaL_checkstack (lua_State *L, int sz, const char *msg);

 lua_pop 从栈中弹出n个元素;

lua_gettop 返回栈顶元素的索引(也即元素个数);

lua_concat 将栈顶开始的n个元素连接起来,并将它们出栈,然后将结果入栈;

lua_getfield 将t[k]压入堆栈,t由参数index指定在栈中的位置;

lua_setfield 相当于t[k]=v,t由参数index指定在栈中的位置,v是栈顶元素,改函数会将栈顶的value出栈;

lua_getglobal(L,s) 等价于 lua_getfield(L, LUA_GLOBALSINDEX, s),注意:栈中LUA_GLOBALSINDEX索引位置处是当前Lua状态机的全局变量环境。

lua_setglobal(L,s) 等价于 lua_setfield(L, LUA_GLOBALSINDEX, s);

lua_insert 移动栈顶元素到index指定的位置;

lua_remove 移除index处的元素,index之上的元素均下移一个位置;

lua_replace 将栈顶元素移到指定位置,并取代原来的元素,原先的栈顶元素弹出;

lua_next 弹出一个key,然后将t[key]入栈,t是参数index处的table;在利用lua_next遍历栈中的table时,对key使用lua_tolstring尤其需要注意,除非知道key都是string类型。

lua_objlen 返回index处元素的长度,对string,返回字符串长度;对table,返回"#"运算符的结果;对userdata,返回内存大小;其它类型返回0;

luaL_checkstack 增加栈大小(新增sz个元素的空间),如果grow失败,引发一个错误,msg参数传递错误消息。

 

int lua_isboolean (lua_State *L, int index);
int lua_iscfunction (lua_State *L, int index);
int lua_isfunction (lua_State *L, int index);
int lua_islightuserdata (lua_State *L, int index);
int lua_isnil (lua_State *L, int index);
int lua_isnone (lua_State *L, int index);
int lua_isnoneornil (lua_State *L, int index);
int lua_isnumber (lua_State *L, int index);
int lua_isstring (lua_State *L, int index);
int lua_istable (lua_State *L, int index);
int lua_isthread (lua_State *L, int index);
int lua_isuserdata (lua_State *L, int index);

这些都是栈中指定元素类型检查的接口;

 

 

函数调用

void lua_call (lua_State *L, int nargs, int nresults);
int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);

int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);

lua_call 调用函数,参数nargs指定函数参数个数,参数nresults指定返回值个数。首先,被调函数必须在栈中;其次,函数参数必须是按从左往右的顺序入栈的;函数调用时,所有函数参数都会弹出堆栈。函数返回时,其返回值入栈(第一个返回最最先入栈)。

lua_pcall 以保护模式调用函数,如果发生错误,捕捉它,并将错误消息压入栈,然后返回错误码。

lua_cpcall 以保护模式调用C函数func,参数ud指针指向一个用户自定义数据。

 

错误处理

int luaL_error (lua_State *L, const char *fmt, ...);

引发一个错误。

 

类型转换

int lua_toboolean (lua_State *L, int index);
lua_CFunction lua_tocfunction (lua_State *L, int index);
lua_Integer lua_tointeger (lua_State *L, int index);
const char *lua_tolstring (lua_State *L, int index, size_t *len);
lua_Number lua_tonumber (lua_State *L, int index);
const void *lua_topointer (lua_State *L, int index);
const char *lua_tostring (lua_State *L, int index);
lua_State *lua_tothread (lua_State *L, int index);
void *lua_touserdata (lua_State *L, int index);

lua_toboolean 将给定index索引处的元素转换为bool类型(0或1);
lua_tocfunction 将给定index索引处的元素转换为C函数;
lua_tointeger 将给定index索引处的元素转换为int类型;
lua_tolstring 将给定index索引处的元素转换为char*类型,如果len不为空,同时还设置len为字符串长度;该函数返回的指针,指向的是Lua虚拟机内部的字符串,这个字符串是以'\0'结尾的,但字符串中间也可能包含值为0的字符。
lua_tostring 等价于参数len=NULL时的lua_tolstring;
lua_tonumber 将给定index索引处的元素转换为double类型;
lua_topointer 将给定index索引处的元素转换为void*类型;
lua_tothread 将给定index索引处的元素转换为lua_State*类型(即一个thread);
lua_touserdata 返回给定index索引处的userdata对应的内存地址;

 

 

thread 操作

lua_State *lua_newthread (lua_State *L);

int lua_resume (lua_State *L, int narg);

int lua_yield (lua_State *L, int nresults);

 

lua_newthread 创建一个新的thread,然后压入堆栈,并返回一个lua_State*指针表示创建的新thread。
新创建的thread与当前thread共享一个全局环境。没有销毁thread的显式调用,它由垃圾收集器负责回收。

 

 

 


 

C 调用 Lua代码

 

一个简单的例子:

// test.c

#include        <stdio.h>
#include        "lua.h"
#include        "lualib.h"
#include        "lauxlib.h"

/*the lua interpreter*/
lua_State* L;

int luaadd(int x, int y)
{
    int sum;

    lua_getglobal(L,"add");

    lua_pushnumber(L, x); 

    lua_pushnumber(L, y); 

    lua_call(L, 2, 1); 

    sum = (int)lua_tonumber(L, -1);

    lua_pop(L,1);

    return sum;
}

int main(int argc, char *argv[])
{
    int sum;

    L = lua_open();

    luaL_openlibs(L);

    luaL_dofile(L, "add.lua");

    sum = luaadd(10, 15);

    printf("The sum is %d \n",sum);

    lua_close(L);

    return 0;
}

注意:在C代码里面我们要引入三个头文件lua.h,lauxlib.h和lualib.h:

lua.h中定义的是最基础的API;

lauxlib.h中的函数都以luaL_开头,他们是比基础API更抽象的函数;

lualib.h中定义了打开标准类库的API,比如luaL_openlibs(L)。

程序开始用luaL_open()函数创建一个lua_State。lua_State中保存了Lua运行时的所有的状态信息(比如变量的值等),并且所有的Lua的C的API都有一个lua_newstate指针的参数。luaL_open函数会创建一个全新的Lua运行时状态,其中没有任何预先定义好的函数(包括最基本的print函数)。如果需要试用标准类库的话,只要调用luaL_openlibs(L)函数就打开标准类库就可以了。标准类库被分别封装在不同的包中,当你需要使用的时候再引入到代码中,这样做的好处是可以使Lua尽可能的小(嵌入式语言必须要小),从而可以方便嵌入到其他语言中去。当Lua运行时状态和标准类库都准备完成后,就可以调用luaL_dofile(L,"test.lua")函数来执行Lua脚本。运行结束后,需要调用lua_close(L)来关闭Lua运行时状态。

 

被调用的test.lua文件:

-- test.lua

function add(x,y)
   return x + y 
end 

编译命令,实际命令需要根据自己的lua环境调整

gcc test.c -o test -llua-5.1 -I /usr/local/include/ 

 

执行./test命令的输出:

The sum is 25 

另外一个操作table的例子:

int main()
{

    lua_State *L = luaL_newstate(); 

    luaL_openlibs(L);  

    lua_newtable(L);  

    lua_pushstring(L, "i am key");

    lua_pushstring(L, "i am value");

    lua_settable(L, -3);  

    lua_pushstring(L, "i am key");

    lua_gettable(L, -2); 

    const char *str = lua_tostring(L, -1);

    printf("%s", str);

    lua_close(L);

    return 0;
}

 

Lua 调用 C 函数

当Lua调用C函数时,也使用了一个与C语言调用Lua时相同的栈。C函数从栈中获取函数参数,并将结果压入栈中。为了在栈中将函数结果与其他值区分开,C函数还应返回其压入栈中的结果个数。
栈不是一个全局性的结构,每个函数都有自己的局部私有栈。当Lua调用一个C函数时,第一个参数总是这个局部栈的索引1。

 

对于可被Lua调用的C函数而言,其接口必须遵循Lua要求的形式,即
typedef int (*lua_CFunction)(lua_State* L);

接收一个参数Lua_State*,即Lua的状态,返回值表示压入栈中的结果个数。

 

把要调用的C 函数注册到lua状态机中:
void lua_register (lua_State *L, const char *name, lua_CFunction f);

lua_register 是一个宏:#define lua_register(L,n,f) (lua_pushcfunction(L, f), lua_setglobal(L, n))

其中,参数name是lua中的函数名,f 是C中的函数。

从宏定义可以看出,这个函数的作用是把C函数压入堆栈,并在全局环境中设置Lua函数名;

 

Lua在require模块的时候,除了搜索 "*.lua" 文件,也会搜索 "*.so" 文件,也就是说,Lua支持加载C/C++语言编译的动态库文件。

// foo.c

#include        "lua.h"
#include        "lualib.h"
#include        "lauxlib.h"

static int add(lua_State *L) 
{
    int n = lua_gettop(L);      /* number of arguments */

    lua_Number sum = 0;

    int i;

    for (i = 1; i <= n; i++) {
        if (!lua_isnumber(L, i)) {
            lua_pushstring(L, "incorrect argument");
            lua_error(L);
        }   

        sum += lua_tonumber(L, i); 
    }   

    lua_pushnumber(L, sum/n);    /* first result */
    lua_pushnumber(L, sum);      /* second result */

    return 2;                    /* number of results */
}

int luaopen_foo(lua_State *L) 
{
    lua_register(L, "add", add);
    return 1;
}

注意:luaopen_MODULE 函数的后缀是有规则的,必须是模块名称,而lua_register的第二个参数是供Lua代码调用的函数名称,第三个参数是当前C函数;

OK,现在把C代码编译成动态库:

gcc foo.c -shared -fPIC -o foo.so  -llua-5.1 -I /usr/local/include/ 

 

然后在lua代码里面可以加载该模块:

require("foo")

这条命令会自动加载foo.so库,并调用其中的 luaopen_foo 函数,然后执行里面的函数注册代码,这样接下来就能直接使用那些注册到Lua状态机里面的C函数了。

print(add(14,25,15))

输出结果:

18      54
Lua C API的垃圾回收探索 (Garbage Collection) Lua和C API是通过一个虚拟栈结构lua_State交互的。关于这个虚拟栈,Lua官方手册给的提示并不多。 首先,lua栈上的对象和值是受到GC控制的。因此这样的代码可能存在一些问题: lua_State* xL=lua_newthread(L); lua_pop(L,1) // work with xL... 在这里,lua_newthread执行后,会有一个新thread被放到L上,然后... 阅读详情

相关推荐

Lua中的线程和状态

线程(thread)作为Lua中一种基本的数据类型,它代表独立的执行线程(independent threads of execution),线程类型是实现协程(coroutines)的基础。本文将介绍Lua虚拟中的全局状态和线程的关系,以及从源码角度来看其数据结构。

MaximusZhou的专栏 1万+

Lua 与C交互

Lua和C之间的交互 (一) Lua 调C函数 什么样类型的函数可以被Lua调用 typedef int (*lua_CFunction) (lua_State *L); 符合类型的函数怎样处理后才可以被Lua调用 使用lua_register或者 lua_pushfunction和lua_setglobal()把...

bitssly的博客 763

Lua与c交互原理

介绍 Lua与C交互的高级用法,进阶到高级、资深必知必会的知识点

lpl312905509的博客 1242

Lua与C的交互

Lua 与 C 的交互   Lua是一个嵌入式的语言,它不仅可以是一个独立运行的程序,也可以是一个用来嵌入其它应用的程序库。 C API是一个C代码与Lua进行交互的函数集,它由以下几部分构成: 1、  读写Lua全局变量的函数; 2、  调用Lua函数的函数; 3、  运行Lua代码片段的函数; 4、  注册C函数后可以在Lua中被调用的函数;   在C和LUA之间交互的关键在...

weixin_34377065的博客 342

Lua与宿主语言(C/C++)交互原理

Lua语言可研究的东西真是多,各种机制原理:与宿主语言(下文均指C/C++)的交互、内存管理(垃圾回收)、虚拟机实现、协程、闭包、异常捕获机制等。如取其一进行研究,要吃透还是需要点时间和精力。相信只要一点点慢慢啃,终究还是会将其吸收。 以下的相关原理介绍是基于Lua-5.1.5版本的源码,不排除与之后版本的源码中有少部分差异存在,但基本原理应该相同。

Jonny 8027

lua和c/c++交互

lua 和c采用虚拟栈的方式传递数据,栈中的元素是以lua 数据结构的方式存储,

Waorange的博客 1598

Lua与C之间的交互

Lua与C之间的交互一、Lua与C之间的交互1.1 C调用lua函数 一、Lua与C之间的交互 1.1 C调用lua函数 代码: test.lua: function add(x, y) return x + y end test.c: #include <stdio.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" int lua_add(lua_State *L) { lua_getg

kanguolaikanguolaik的专栏 351

Lua常用C API与C/C++交互

“Lua handles a chunk as the body of an anonymous function with a variable number of arguments”这是Lua对chunk也就是lua文件的处理方式,就是认为是一个可变参数的匿名函数。也就是说,调用后栈上有一个匿名函数,这个函数的body就是文件中所有的内容。

悦分享 1213

Lua 基础之与 C 交互

lua 是一种嵌入语言,并不能独立运行,而是一个可以链接到其它应用程序的库。lua 是使用 c 语言开发的,因此它与 c 语言的交互非常简单,但 lua 作为一门十分流行的脚本语言,不仅能嵌入到语言中,还能嵌入到 java,c# 等其它语言中。lua 与 c 语言的交互方式有两种,一种是以 c 语言为主,lua 作为 c 语言调用的一个库,这种方式的 c 代码称为 应用程序代码

xingxinmanong的博客 683

STM32+ST7789屏实战:手把手教你打造物理按键控制的3级菜单GUI(附完整代码)

本文详细介绍了如何使用STM32和ST7789屏构建物理按键控制的3级菜单GUI系统。从硬件架构设计、SPI驱动配置到菜单状态机实现,提供了完整的代码示例和优化技巧,帮助开发者快速掌握嵌入式GUI开发的核心技术。

iii12的专栏 236

多元相关性分析_PAST:最简便易用的统计学分析软件教程目录

欢迎来到PAST的世界!本教程并不是将PAST的所有功能均进行详细介绍,而只是挑选与生物、医学、微生物研究相关的统计学分析内容进行讲述。根据PAST内各项分析的标签分类,将该教程具体设置如下:PAST软件介绍PAST的基本信息数据的输入和修改数据的转换和标准化图像绘制 (Plot标签)点线图和直方图散点图条形图和箱须图饼图堆叠条形图三元相图气泡图单变量统计学分析 (Univariate标...

weixin_39605706的博客 3155

lua和C的交互

一个简单的例子struct Posint x;int y;p->x = v;return 0;p->y = v;return 0;return 1;return 1;p->y = y;p->x = x;return 1;int main()//用于创建一个新的lua虚拟机//打开标准库// 将 table 绑定到全局变量 "g_Cfuns"= LUA_OK)//关闭lua虚拟机return 0;

ZZHinclude的博客 1344

从 Integrated Configuration 到 Integration Flow,SAP PI/PO 老配置迁移的一次温和重构

很多还在运行 SAP PI/PO 的系统,Integration Directory 里都积累了不少 Integrated Configuration,也就是日常项目里常说的 ICO。它们可能稳定运行了多年,负责把采购订单、物料主数据、客户主数据、发票、发货通知从一个系统送到另一个系统。问题在于,ICO 这种对象很实用,却不够直观。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 95

[Lua] Lua与C交互入门

[Lua] Lua与C交互入门 文章目录[Lua] Lua与C交互入门枚举值状态码类型码算符码比较算符码交互类型概念栈函数注释参数记号函数状态机构造和析构状态信息栈操作基本栈操作值操作建值交换函数拉取函数(Lua -> 栈)拉取函数(栈 -> C)探测函数推送函数(C -> 栈)推送函数(栈 -> Lua)算符函数调用函数lua_call(L,na,nr)调用协议 (C -> Lua)lua_pcall(L,na,nr,i)调用协议 (C -> Lua)lua_CFunc

airaou 608

QGis软件 —— 2、QGis加载在线地图两种方式(谷歌地图、天地图)

QGis软件 —— 2、QGis加载在线地图两种方式(谷歌地图)

1万+

uniapp - H5人脸识别认证与活体检测功能(纯前端免费方案+微信sdk人脸识别)完整源码,微信公众号网页/h5端人脸识别功能人脸核身(微信方案提供后端spring boot+thinkphp源码

uniapp实现人脸认证,uniAPP h5手机拍照+人脸识别,免费人脸识别插件,前端人脸识别解决方案,uniapp H5人脸识别带前后摄像头,人脸识别在H5页面进行采集,微信公众号H5人脸核身,H5端人脸识别功能实现,免费h5人脸识别插件方案,微信公众号H5网页实现人脸识别,uniapp人脸监测,uniapp人脸生物监测,使用uniapp开发H5人脸采集功能/人脸识别功能,uniapp项目—h5端人脸采集功能实现,uniapp vue3人脸核身,H5活体检测认证,人脸认证张嘴摇摇头指引动作,人脸核身 微信

🏆 前端领域优质创作者 3808

Linux下lua安装以及和c的交互

lua安装,与c交互的过程记录lua安装 在此我的机器环境是cenos 6.8 我安装的是lua5.1.4版本 安装lua编译的相关依赖 yum -y install readline-devel ncurses-devel tar -zxvf lua-5.1.4.tar.gz cd lua-5.1.4 make linux test make install 至此

猪会飞 2076

CLRNet车道线检测模型在Orin Nano Super开发板上的全栈部署与优化实践

本文详细介绍了将CLRNet车道线检测模型部署到NVIDIA Orin Nano Super开发板的全过程。内容包括:1) Orin开发板硬件规格分析;2) JetPack SDK环境配置与Python虚拟环境搭建;3) CLRNet模型架构解析与PyTorch实现;4) 模型转换与TensorRT加速优化方法。通过系统性的环境配置、模型转换和性能优化,为边缘计算场景下的车道线检测应用提供了完整的解决方案,实现了在Orin平台上的高效部署。

huanghm88的专栏 226

lua与c交互

Lua_State 动态结构这个结构是虚拟机运行起来最重要的结构体用 Lual_newstate 创建一个新的环境 lualib.h 定义了打开标准库的函数 Lual_openlibs 可以打开所有的标准库 创建好状态 在加载了标准库以后就能解释用户的输入了。Lua 和 c 的交互全在虚拟站里面进行。 虚拟栈解决了lia和c 的两大差异 1>lua的垃圾收集 2>c是静态类型 l

梁平平的博客 623

OpenClaw小白使用全攻略

OpenClaw全能技能解锁指南:从基础到进阶 摘要: 本文提供OpenClaw AI智能体的完整使用教程,帮助用户从安装后"不知道如何用"到熟练掌握核心功能。教程包含:1)控制台5大区域详解和3个必做初始化设置;2)文件管理、浏览器自动化、文档生成等5大基础功能实操,每个功能配有详细操作步骤、指令模板和效果演示;3)10+高频场景解决方案,如整理文件、搜集资料、写总结等;4)进阶技巧和常见问题解答。通过清晰的图文指引,即使电脑小白也能快速上手,实现办公自动化、提升工作效率。

通俗易懂学IT 3057

HandwrittenMathFormulaRecognition:基于YOLOv8的手写数学公式识别系统

输入:包含手写数学公式的图像(拍摄的板书、作业纸等)输出:对应的数字文本形式的数学公式(如LaTeX格式或文本表达式)标准的手写数学表达式数据集,包含在线轨迹及图片,广泛用于公式识别研究。包含近10万对公式图片及对应的LaTeX标注,适合训练公式识别模型。MathBrush公开手写数学公式图像数据集,含多种书写风格。手写数字与符号数据集(MNIST及其扩展)用于基础数学符号的训练。

YOLO 283

lua android 交互,lua和c之交互

xxg@xxg-desktop:~/1-wire/hellolua/src$ ./luatest--> Hello LUA, this is my first lua program for yingying!lua: average = 30C:crc8-->argument 1, Len = 12, Data = 313233343536, return 0xECC:crc8--&...

weixin_35794280的博客 584

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

c与lua交互 二

(一) lua 代码     --Lua的字符串模式       szMode = "(%w+)%s*=%s*(%w+)";       --要处理的字符串       szStr = "key1 = value1 key2 = value2";        --目标字符串模式       szTag = "%2";     r = string.gsub(szStr

wusthongmin的专栏 796

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Lua和C交互的简易教程

转载请标明出处:http://blog.youkuaiyun.com/shensky711/article/details/52458051 本文出自: 【HansChen的博客】 Lua栈要理解Lua和C++交互,首先要理解Lua堆栈。简单来说,Lua和C/C++语言通信的主要方法是一个无处不在的虚拟栈。栈的特点是先进后出.在Lua中,Lua堆栈就是一个struct,堆栈索引的方式可是是正数也可以是负数

HansChen的博客 6512
上一篇: 将exe和dll文件打包成单一的启动文件
下一篇: Running LuaJIT
CoderAldrich
博客等级 码龄12年 431粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值