ctypes给扩展模块中的函数传递回调函数

Posted traditional

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ctypes给扩展模块中的函数传递回调函数相关的知识,希望对你有一定的参考价值。

C语言中的回调函数

什么是回调函数我就不介绍了,我们先来看看C语言中如何使用回调函数。

函数指针

不过在看回调函数之前,我们先看看如何把一个函数赋值给一个变量。准确的说,是让一个指针指向一个函数,这个指针叫做函数指针。通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。函数指针可以像一般函数一样,用于调用函数、传递参数。

#include <stdio.h>

int add(int a, int b){
  int c;
  c = a + b;
  return c;
}

int main(int argc, char const *argv[]) {
  //创建一个指针变量p,让p等于指向add
  //我们看到就类似声明函数一样,指定返回值类型和变量类型即可
  //但是注意的是,中间一定是*p,不是p,因为这是一个函数指针,所以要有*
  int (*p)(int, int) = add;
  printf("1 + 3 = %d
", p(1, 3)); //1 + 3 = 4
  return 0;
}

除此之外我们还以使用typedef

#include <stdio.h>


int add(int a, int b){
  int c;
  c = a + b;
  return c;
}

//相当于创建了一个类型,名字叫做func。这个func表示的是一个函数指针类型
typedef int (*func)(int, int);

int main(int argc, char const *argv[]) {
  //声明一个func类型的函数指针p,指向add函数
  func p = add;
  printf("2 + 3 = %d
", p(2, 3)); //2 + 3 = 5
  return 0;
}

使用回调函数

下面来看看如何使用回调函数,说白了就是把一个函数指针作为函数的参数

#include <stdio.h>

char *evaluate(int score){
  if (score < 60 && score >= 0){
    return "不及格";
  }else if (score < 80){
    return "及格";
  }else if (score < 90){
    return "不错";
  }else if (score <=100){
    return "真棒";
  }else {
    return "无效的成绩";
  }
}

//接收一个整型和一个函数,函数接收一个整型返回char *
char *execute1(int score, char *(*f)(int)){
  return f(score);
}

//除了上面那种方式,我们还可以跟之前一样通过typedef
typedef char *(*func)(int);
//这样声明也是可以的。
char *execute2(int score, func f){
  return f(score);
}


int main(int argc, char const *argv[]) {
  printf("%s
", execute1(88, evaluate)); //不错
  printf("%s
", execute2(70, evaluate)); //及格
}

python向C语言传递回调函数

我们知道了在C中传入一个函数,那么在python中如何定义一个C语言可以识别的函数呢?毫无疑问,类似于结构体,我们肯定是要先定义一个python的函数,然后再把python的函数转化成C语言可以识别的函数。

int add(int a, int b, int (*f)(int *, int *)){
  return f(&a, &b);
}

我们就以这个函数为例,add函数返回一个int,接收两个int,和一个函数指针,那么我们如何在python中定义这样的函数并传递呢?我们来看一下,不过我们记得要编译成扩展模块:gcc?-o dll或者so -shared c源文件,这里编译成mmp.dll

from ctypes import *

lib = CDLL("./mmp.dll")


# 扩展函数中接收的函数的参数是两个int *,所以我们这里的a和b也是一个pointer
def add(a, b):
    return a.contents.value + b.contents.value


# 此时我们把C中的函数用python表达了,但是这样肯定是不可能直接传递的,能传就见鬼了
# 那我们要如何转化呢?
# 可以通过ctypes里面的函数CFUNCTYPE转化一下,这个函数接收任意个参数
# 但是第一个参数是函数的返回值类型,然后函数的参数写在后面,有多少写多少。
# 比如这里的函数返回一个int,接收两个int *,所以就是
t = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
# 如果函数不需要返回值,那么写一个None即可
# 然后得到一个类型t,此时的类型t就等同于C中的 typedef int (*t)(int*, int*);
# 将我们的函数传进去,就得到了C语言可以识别的函数func
func = t(add)
# 然后调用,别忘了定义返回值类型,当然这里是int就无所谓了
lib.add.restype = c_int
print(lib.add(88, 96, func))
print(lib.add(59, 55, func))
print(lib.add(94, 105, func))
"""
184
114
199
"""

技术图片

以上是关于ctypes给扩展模块中的函数传递回调函数的主要内容,如果未能解决你的问题,请参考以下文章

通过DOM元素数据集将回调传递给js

Python 对象作为 ctypes 回调函数中的用户数据

ctypes获取扩展模块中函数的返回值

将 FILE * 从 Python / ctypes 传递给函数

函数名作为参数传递与回调函数

Ctypes将float传递给函数返回随机数