调用一个动态库中的函数,这个函数有一个参数是结构体指针,我如何使用这个指针?

author author     2023-03-18     513

关键词:

我是希望利用动态库中的结构体指针,它就好比是一个返回值。在我自己的函数里定义了一个结构体指针,将其传递给这个动态库中的函数,将动态库函数中的结构体指针赋给我定义的结构体指针,但其值并不是动态库函数中结构体指针的值,怎么办?
我已经定义了一个形参中结构体指针,指向我想要的结构体指针,但调用以后发现形参中的结构体指针并未改变,麻烦高手帮帮忙啊
我定义的指针在传递过程中允许其地址改变么?

你就也定义一个形参中的结构体指针接收传过来的结构体指针就OK啦
形参中的结构体指针改变?这什么意思?
给你看个例子吧:
struct node *creat(struct node *l)

struct node *head;
head=l;
return head;

你是这样吗~追问

就是主程序中定义了一个结构体指针1,将其作为形参传递给某个调用函数,在函数内部又给这个形参赋值了一个结构体指针2,这样这个形参结构体指针1指向的地址就发生了改变,那在主程序中它的地址也改变么?我怎么发现他指向的地址没有改变呢?这样我怎么能够使用调用函数中的那个结构体指针2呢?
PS:调用函数的返回类型已经确定,所以这个结构体指针必须作为形参来传递

追答

不能说是给这个形参赋值了一个结构体指针2,而是应该说用以个结构体指针2接收形参
地址是没变啊 你的做法是将结构体指针2指向你传过来的结构体指针1的地址,所以指针1 2所指向的地址是相同的
你把结构体指针2返回就可以啦

追问

我是想让结构体指针1的地址改变成结构体指针2的地址,并且struct *p1=shtrcut *p2是将p1指向了p2的地址吧?形参p1地址改变了,这样是对的吧?

参考技术A 扩展Lua的基本方法之一就是为应用程序注册新的C函数到Lua中去。
当我们提到Lua可以调用C函数,不是指Lua可以调用任何类型的C函数(有一些包可以让Lua调用任意的C函数,但缺乏便捷和健壮性)。正如我们前面所看到的,当C调用Lua函数的时候,必须遵循一些简单的协议来传递参数和获取返回结果。相似的,从Lua中调用C函数,也必须遵循一些协议来传递参数和获得返回结果。另外,从Lua调用C函数我们必须注册函数,也就是说,我们必须把C函数的地址以一个适当的方式传递给Lua解释器。
当Lua调用C函数的时候,使用和C调用Lua相同类型的栈来交互。C函数从栈中获取她的参数,调用结束后将返回结果放到栈中。为了区分返回结果和栈中的其他的值,每个C函数还会返回结果的个数(the function returns (in C) the number of results it is leaving on the stack.)。这儿有一个重要的概念:用来交互的栈不是全局变量,每一个函数都有他自己的私有栈。当Lua调用C函数的时候,第一个参数总是在这个私有栈的index=1的位置。甚至当一个C函数调用Lua代码(Lua代码调用同一个C函数或者其他的C函数),每一个C函数都有自己的独立的私有栈,并且第一个参数在index=1的位置。
26.1 C 函数
先看一个简单的例子,如何实现一个简单的函数返回给定数值的sin值(更专业的实现应该检查他的参数是否为一个数字):
static int l_sin (lua_State *L)
double d = lua_tonumber(L, 1); /* get argument */
lua_pushnumber(L, sin(d)); /* push result */
return 1; /* number of results */

任何在Lua中注册的函数必须有同样的原型,这个原型声明定义就是lua.h中的lua_CFunction:
typedef int (*lua_CFunction) (lua_State *L);
从C的角度来看,一个C函数接受单一的参数Lua state,返回一个表示返回值个数的数字。所以,函数在将返回值入栈之前不需要清理栈,函数返回之后,Lua自动的清除栈中返回结果下面的所有内容。
我们要想在Lua使用这个函数,还必须首先注册这个函数。我们使用lua_pushcfunction来完成这个任务:他获取指向C函数的指针,并在Lua中创建一个function类型的值来表示这个函数。一个quick-and-dirty的解决方案是将这段代码直接放到lua.c文件中,并在调用lua_open后面适当的位置加上下面两行:
lua_pushcfunction(l, l_sin);
lua_setglobal(l, "mysin");
第一行将类型为function的值入栈,第二行将function赋值给全局变量mysin。这样修改之后,重新编译Lua,你就可以在你的Lua程序中使用新的mysin函数了。在下面一节,我们将讨论以比较好的方法将新的C函数添加到Lua中去。
对于稍微专业点的sin函数,我们必须检查sin的参数的类型。有一个辅助库中的luaL_checknumber函数可以检查给定的参数是否为数字:当有错误发生的时候,将抛出一个错误信息;否则返回作为参数的那个数字。将上面我们的函数稍作修改:
static int l_sin (lua_State *L)
double d = luaL_checknumber(L, 1);
lua_pushnumber(L, sin(d));
return 1; /* number of results */

根据上面的定义,如果你调用mysin('a'),会得到如下信息:
bad argument #1 to 'mysin' (number expected, got string)
注意看看luaL_checknumber是如何自动使用:参数number(1),函数名("mysin"),期望的参数类型("number"),实际的参数类型("string")来拼接最终的错误信息的。
下面看一个稍微复杂的例子:写一个返回给定目录内容的函数。Lua的标准库并没有提供这个函数,因为ANSI C没有可以实现这个功能的函数。在这儿,我们假定我们的系统符合POSIX标准。我们的dir函数接受一个代表目录路径的字符串作为参数,以数组的形式返回目录的内容。比如,调用dir("/home/lua")可能返回".", "..", "src", "bin", "lib"。当有错误发生的时候,函数返回nil加上一个描述错误信息的字符串。
#include <dirent.h>
#include <errno.h>

static int l_dir (lua_State *L)
DIR *dir;
struct dirent *entry;
int i;
const char *path = luaL_checkstring(L, 1);

/* open directory */
dir = opendir(path);
if (dir == NULL) /* error opening the directory? */
lua_pushnil(L); /* return nil and ... */
lua_pushstring(L, strerror(errno)); /* error message */
return 2; /* number of results */


/* create result table */
lua_newtable(L);
i = 1;
while ((entry = readdir(dir)) != NULL)
lua_pushnumber(L, i++); /* push key */
lua_pushstring(L, entry->d_name); /* push value */
lua_settable(L, -3);


closedir(dir);
return 1; /* table is already on top */

辅助库的luaL_checkstring函数用来检测参数是否为字符串,与luaL_checknumber类似。(在极端情况下,上面的l_dir的实现可能会导致小的内存泄漏。调用的三个Lua函数lua_newtable、lua_pushstring和lua_settable可能由于没有足够的内存而失败。其中任何一个调用失败都会抛出错误并且终止l_dir,这种情况下,不会调用closedir。正如前面我们所讨论过的,对于大多数程序来说这不算个问题:如果程序导致内存不足,最好的处理方式是立即终止程序。另外,在29章我们将看到另外一种解决方案可以避免这个问题的发生)
26.2 C 函数库
一个Lua库实际上是一个定义了一系列Lua函数的chunk,并将这些函数保存在适当的地方,通常作为table的域来保存。Lua的C库就是这样实现的。除了定义C函数之外,还必须定义一个特殊的用来和Lua库的主chunk通信的特殊函数。一旦调用,这个函数就会注册库中所有的C函数,并将他们保存到适当的位置。像一个Lua主chunk一样,她也会初始化其他一些在库中需要初始化的东西。
Lua通过这个注册过程,就可以看到库中的C函数。一旦一个C函数被注册之后并保存到Lua中,在Lua程序中就可以直接引用他的地址(当我们注册这个函数的时候传递给Lua的地址)来访问这个函数了。换句话说,一旦C函数被注册之后,Lua调用这个函数并不依赖于函数名,包的位置,或者调用函数的可见的规则。通常C库都有一个外部(public/extern)的用来打开库的函数。其他的函数可能都是私有的,在C中被声明为static。
当你打算使用C函数来扩展Lua的时候,即使你仅仅只想注册一个C函数,将你的C代码设计为一个库是个比较好的思想:不久的将来你就会发现你需要其他的函数。一般情况下,辅助库对这种实现提供了帮助。luaL_openlib函数接受一个C函数的列表和他们对应的函数名,并且作为一个库在一个table中注册所有这些函数。看一个例子,假定我们想用一个我们前面提过的l_dir函数创建一个库。首先,我们必须定义库函数:
static int l_dir (lua_State *L)
... /* as before */

第二步,我们声明一个数组,保存所有的函数和他们对应的名字。这个数组的元素类型为luaL_reg:是一个带有两个域的结构体,一个字符串和一个函数指针。
static const struct luaL_reg mylib [] =
"dir", l_dir,
NULL, NULL /* sentinel */
;
在我们的例子中,只有一个函数l_dir需要声明。注意数组中最后一对必须是NULL, NULL,用来表示结束。第三步,我们使用luaL_openlib声明主函数:
int luaopen_mylib (lua_State *L)
luaL_openlib(L, "mylib", mylib, 0);
return 1;

luaL_openlib的第二个参数是库的名称。这个函数按照指定的名字创建(或者reuse)一个表,并使用数组mylib中的name-function对填充这个表。luaL_openlib还允许我们为库中所有的函数注册公共的upvalues。例子中不需要使用upvalues,所以最后一个参数为0。luaL_openlib返回的时候,将保存库的表放到栈内。luaL_openlib函数返回1,返回这个值给Lua。(The luaopen_mylib function returns 1 to return this value to Lua)(和Lua库一样,这个返回值是可选的,因为库本身已经赋给了一个全局变量。另外,像在Lua标准库中的一样,这个返回不会有额外的花费,在有时候可能是有用的。)
完成库的代码编写之后,我们必须将它链接到Lua解释器。最常用的方式使用动态连接库,如果你的Lua解释器支持这个特性的话(我们在8.2节已经讨论过了动态连接库)。在这种情况下,你必须用你的代码创建动态连接库(windows下.dll文件,linux下.so文件)。到这一步,你就可以在Lua中直接使用loadlib加载你刚才定义的函数库了,下面这个调用:
mylib = loadlib("fullname-of-your-library", "luaopen_mylib")
将luaopen_mylib函数转换成Lua中的一个C函数,并将这个函数赋值给mylib(那就是为什么luaopen_mylib必须和其他的C函数有相同的原型的原因所在)。然后,调用mylib(),将运行luaopen_mylib打开你定义的函数库。
如果你的解释器不支持动态链接库,你必须将你的新的函数库重新编译到你的Lua中去。除了这以外,还不要一些方式告诉独立运行的Lua解释器,当他打开一个新的状态的时候必须打开这个新定义的函数库。宏定义可以很容易实现这个功能。第一,你必须使用下面的内容创建一个头文件(我们可以称之为mylib.h):
int luaopen_mylib (lua_State *L);

#define LUA_EXTRALIBS "mylib", luaopen_mylib ,
第一行声明了打开库的函数。第二行定义了一个宏LUA_EXTRALIBS作为函数数组的新的入口,当解释器创建新的状态的时候会调用这个宏。(这个函数数组的类型为struct luaL_reg[],因此我们需要将名字也放进去)
为了在解释器中包含这个头文件,你可以在你的编译选项中定义一个宏LUA_USERCONFIG。对于命令行的编译器,你只需添加一个下面这样的选项即可:
-DLUA_USERCONFIG=\"mylib.h\"
(反斜线防止双引号被shell解释,当我们在C中指定一个头文件时,这些引号是必需的。)在一个整合的开发环境中,你必须在工程设置中添加类似的东西。然后当你重新编译lua.c的时候,它包含mylib.h,并且因此在函数库的列表中可以用新定义的LUA_EXTRALIBS来打开函数库。

参考资料:百度一下

参考技术B 不熟

161-结构函数的定义和使用

...个函数的时候,这个函数就可以通过结构体声明的变量来调用,这个函数可以带有参数,那么调用的时候必须传递参数,这个函数,可以使用结构体中的属性。structCustomerNamepublicstringFirstName;publicstringLastName;publicstringGetName()returnFi... 查看详情

结构体作为函数参数值传递的问题

...针二者都可以作为传出参数,因为接受函数必须为其定义一个结构指针来接收,这样在函数内就可以修改结构体,在这点上二者没有区别。定义结构体指针未分配地址空间就作为参数传递会,如果你想把它作为传出参数的话,你... 查看详情

c语言结构体函数的返回值是结构体结构体变量中的信息

...,那岂不是函数返回只会有多个。但是C语言函数只能有一个返回值啊。还有有些程序里在最后写一个return;并没有写0或1,而是什么都没写。这样写的作用是什么?你说的这种情况,函数返回的是整个结构体,无论这个结构体中... 查看详情

c语言结构体函数的返回值是结构体结构体变量中的信息

...,那岂不是函数返回只会有多个。但是C语言函数只能有一个返回值啊。还有有些程序里在最后写一个return;并没有写0或1,而是什么都没写。这样写的作用是什么?你说的这种情况,函数返回的是整个结构体,无论这个结构体中... 查看详情

如何将不同类型的结构体作为一个函数的参数?

...个函数func(A&c)....func(B&c).....这样你传A类型的参数,就会调用前面的那个函数,你传B类型的参数,就会调用后面的那个函数。虽然写了两个函数,但却相当于定义了一个可接受不同类型参数的函数,不知符合你的要求不。参考技... 查看详情

什么是回调函数麻烦告诉我

...),最终让原函数返回一个值使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数... 查看详情

谈谈结构体

...们只要将一个_calendar_obj这个结构体类型的变量作为实参调用DsipDateTime()即可,DsipDateTime()通过DateTimeVal的成变量来实现内容的显示。如果不用结构体,我们很可能需要写这样的一个函数:  显然这样的形参很不可观,数据... 查看详情

结构体数组怎么做函数参数

...可以直接用么追答那就在自定义函数中不用自变量i,在调用时给地址加1就可以了直接进行操作参考技术A以C/C++为例,数组作为函数参数会转化为指针,结构体数组也不例外,会转化为指向该结构体类型的指针。比如structA;voidfoo(... 查看详情

如何识别ida反汇编中动态链接库中的函数

...汇编时,如果正在逆向的文件中有动态链接库函数(比如调用了程序自定义so库中的函数),IDA只会显示一个地址,跟进去会发现是延迟绑定中关于plt的代码,无法知道具体调用了哪个函数,对于逆向起来很是麻烦,本文介绍如... 查看详情

什么是钩子函数?钩子函数的使用。

...钩子函数”,当每次发生您感兴趣的事件时,WINDOWS都将调用该函数。一共有两种类型的钩子:局部的和远程的。局部钩子仅钩挂您自己进程的事件。远程的钩子还可以将钩挂其它进程发生的事件。远程的钩子又有两种:基于线... 查看详情

go语言的reflect(反射)

...字段、方法);3、通过反射,可以修改变量的值,可以调用关联的方法;4、使用反射,需要import"reflect".5、示意图:1、不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这种需要对函数或方法反射... 查看详情

c语言中函数调用怎么返回两个值

在主函数中调用了一个函数,我希望能有两个返回值,在调用函数中怎么去return?好像默认的是只能返回一个值吧!各位,帮帮忙(C语言)在C语言中,函数只能返回一个值,要返回两个值,可以改换思路,通过其它方式做到。1... 查看详情

多个线程同时调用一个函数的情况

...t;存在栈上-->每个线程都有自己的栈),那么多线程同时调用是没关系的,因为用的都是本线程的数据;但是如果函数用到一些全局数据,比如全局变量,根据堆内存首地址去访问的堆内存(形参传入的),同时操作一个数据结构(... 查看详情

带你了解—方法(代码片段)

...收者的;而方法是有接收者的,我们说的方法要么是属于一个结构体的,要么属于一个新定义的类型的。方法的声明和函数类似,他们的区别是:方法在定义的时候,会在func和方法名之间增加一个参数,这个参数就是接收者,... 查看详情

c语言里面的结构体是啥意思

...员可以为不同的类型,成员一般用名字访问。扩展资料将一个结构体变量中的数据传递给另一个函数,有下列3种方法:(1)用结构体变量名作参数。一般较少用这种方法。(2)用指向结构体变量的指针作实参,将结构体变量的地址... 查看详情

C - 具有动态参数数量的调用函数

】C-具有动态参数数量的调用函数【英文标题】:C-callfunctionwithdynamicnumberofarguments【发布时间】:2015-05-3123:43:58【问题描述】:我有一个带有特定数量参数的C函数(不是varargs函数)。例如:voidtestfunction(inta,intb,intc);这个函数是... 查看详情

panicrecover(代码片段)

...o语言的源代码是由数据结构runtime._panic表示的。每当我们调用panic都会创建一个如下所示的数据结构存储相关信息:type_panicstruct argpunsafe.Pointer arginterface link*_panic recoveredbool abortedbool pcuintptr spunsafe.Pointer goexitbool结构体中字段含义... 查看详情

如何动态调用c函数(代码片段)

JSPatch 支持了动态调用C函数,无需在编译前桥接每个要调用的C函数,只需要在JS里调用前声明下这个函数,就可以直接调用:我们一步步来看看怎样可以做到动态调用C函数。函数地址首先若要动态调用C函数,第一步就是需... 查看详情