Python中Ctypes库与回调函数

原新浪博客(http://blog.sina.com.cn/billsona)搬迁至此。

近期项目组开发了一个dylib动态库,我主要负责对这个动态库进行测试,这期间碰到了一个回调函数的问题。说的直白一点,就是模拟上层应用调用dylib动态库的时候,dylib动态库还要回调上层应用提供的接口。
博主脑子转悠的不够快,绕来绕去,成功把我绕晕了。费了好长时间才理清楚其中的逻辑与关系。好记性不如烂笔头,赶紧记下来,防止后面又忘记了。
下面是用visio简单画的逻辑示意图,便于理解。
在这里插入图片描述
下面分步解析并实现一个回调函数的实例。
先用文本文件写一个简单的C程序,写完之后保存成libtest.c文件,代码如下。
在这里插入图片描述
程序解释:定义了一个名为max的void类型的函数,这个函数有3个参数,前面两个是int类型的参数,后面一个是一个返回值为int类型的函数的指针。在这个函数内部,处理也比较简单,实际上就是把前面两个参数传递给指针指向的函数去处理。从上面第三个参数也可以看出来,指针指向的函数处理完之后返回的是一个整形数据。
在mac上,通过命令行执行如下的命令,就可以把上面简单的C程序编译成dylib动态库。

gcc -shared -o libtest.dylib -fPIC libtest.c

这样就产生了一个简单的动态库文件,功能跟上面的C程序保持一致,不多解释。
下面来说说上述C程序中定义的函数中的第三个参数对应的函数。很显然,这个函数没有在上面的C程序中实现,我们在Python中实现,代码如下,很简单。

在这里插入图片描述
这几行代码太简单了,没啥好解释的,功能就是打印第一个参数a的类型,然后打印给定的两个数中较大的一个,最后返回这个较大的数。
到了这里,聪明的读者们可能已经猜到了,这个就是提供给动态库中的函数的第三个参数指向的函数函数吧,功能定义基本一样,给定两个int,返回一个int。
答案是否定的,我当时就是太“聪明”了,一直是这么认为了,在这个地方绕了半天没有绕出来。
下面通过两个问题来解释一下为什么这个函数不能直接给动态库中的函数当参数来调用。
首先,动态库是C程序,这个函数是Python程序,C程序能够直接调用Python程序吗?
其次,虽然这里不管是C还是Python都涉及到int型变量,C中的int和Python中的int是一样的吗?
很显然,这两个问题的答案都是否定的,C程序没法直接调用Python函数,C中的整型和Python中的整型虽然都标记为int,但是两者是不一样的。
这也是ctypes库存在的必要性。这个库为Python和C的混合编程提供了很多有用的方法。比如,Python调用动态库的方法,回调函数的方法,还有能够在Python和C上兼容的数据类型(上面提到了虽然C和Python中相同的数据类型都标记为int,但是实际上两者在机器中的形态可能是不一样的,ctypes库中的数据类型提供了这种兼容性,比如这里兼容int的c_int类型)。
在ctypes中,通过关键字CFUNCTYPE来声明一个回调函数的类型(通过关键字的字面意思也能够看出来,C-FUNC-TYPE,那就是C语言的函数(FUNC)类型(TYPE)嘛,理解了以后,感觉一切都很明了,之前不理解的时候,满脑子浆糊,这是些什么狗屁玩意儿…)。
我们可以用下面一行python语句来声明一个上述C程序中需要调用的回调函数的类型,并把这个回调函数类型实例化,回调函数类型实例就叫CMPFUNC。

CMPFUNC = CFUNCTYPE(c_int, c_int, c_int)

眼尖的同学可能已经发现了,上面不是求要获得两个数中最大的一个吗,这里声明回调函数类型的时候怎么变成了三个参数?其实吧,这里只是指的数据类型,并不是参数本身,后面两个c_int指的是传递给回调函数的参数类型,第一个c_int指的是回调函数的返回值类型。只有这样定义,C程序才能认识。
到了这里,核心内容基本就阐述完毕了,下面附上完整的Python程序代码及相关的注释说明和执行结果。
在这里插入图片描述
执行结果如下

在这里插入图片描述

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Python,要调用C语言的回调函数,需要使用ctypesctypesPython的外部函数,它提供了与C语言函数交互的接口。 首先,我们需要在Python代码导入ctypes,以便使用其功能。 接下来,我们需要定义一个C语言回调函数,并通过ctypes的CFUNCTYPE函数声明函数类型和参数类型。然后,我们将C语言回调函数的指针传递给Python函数。 在Python,我们可以使用ctypes.CDLL函数加载C语言动态链接,并通过函数名调用C语言回调函数。 下面是一个简单的示例代码,演示了如何在Python调用C语言的回调函数: import ctypes # 定义C语言回调函数 def my_callback_function(number): print("C语言回调函数被调用,传递的参数是:", number) # 声明C语言回调函数的类型 CallbackFunc = ctypes.CFUNCTYPE(None, ctypes.c_int) # 将Python函数转换为C语言回调函数 c_callback = CallbackFunc(my_callback_function) # 加载C语言动态链接 c_lib = ctypes.CDLL("my_c_lib.so") # 假设my_c_lib.so是C语言动态链接 # 调用C语言回调函数 c_lib.call_callback(c_callback) 在上面的示例,我们定义了一个名为my_callback_function的Python函数作为C语言回调函数。然后,我们使用CFUNCTYPE函数声明了C语言回调函数的类型,指定了参数类型和返回类型。 通过CallbackFunc函数Python函数转换为C语言回调函数,并将其传递给C语言动态链接的call_callback函数。 当C语言动态链接的call_callback函数被调用时,C语言回调函数会被执行,同时将参数传递给Python的my_callback_function函数。 这样,我们就可以在Python成功调用C语言的回调函数了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值