在多个模块中使用函数类型时出现错误签名

3 投票
2 回答
1365 浏览
提问于 2025-04-18 01:13

我有以下的Cython模块:

compmech    
    integrate
        integratev.pxd
        integratev.pyx
    conecyl
        main.pyx

integratev.pxd文件中,我声明了:

ctypedef void (*f_type)(int npts, double *xs, double *ts, double *out,
                    double *alphas, double *betas, void *args) nogil

cdef int trapz2d(f_type f, int fdim, np.ndarray[cDOUBLE, ndim=1] final_out,
                 double xmin, double xmax, int m,
                 double ymin, double ymax, int n,
                 void *args, int num_cores)

我在main.pyx中调用trapz2d,并且传给trapz2d的函数也是在main.pyx中声明的,比如:

from compmech.integrate.integratev cimport trapz2d

cdef void cfk0L(int npts, double *xs, double *ts, double *out,
                double *alphas, double *betas, void *args) nogil:
    ...

trapz2d(<f_type>cfk0L, fdim, k0Lv, xa, xb, nx, ta, tb, nt, &args, num_cores)

编译的时候一切都很好,但当我运行时却出现了错误:

TypeError: C function compmech.integrate.integratev.trapz2d has wrong signature       
(expected int (__pyx_t_8compmech_9integrate_10integratev_f_type, int, PyArrayObject *,
               double, double, int, double, double, int, void *, int),
 got int (__pyx_t_10integratev_f_type, int, PyArrayObject *,
          double, double, int, double, double, int, void *, int))

我觉得这可能是个bug,但也许我在这里漏掉了什么重要的东西……


注意:如果我把所有内容都放在main.pyx里,而不是使用多个模块,它就能正常工作。

2 个回答

0

解决办法是把所有东西都当作 void * 类型来传递,然后在实际执行函数之前,也就是在 trapz2d() 里面,把它转换成 <f_type> 类型。最终的代码布局是:

ctypedef void (*f_type)(int npts, double *xs, double *ts, double *out,
                    double *alphas, double *betas, void *args) nogil

cdef int trapz2d(void *fin, int fdim, np.ndarray[cDOUBLE, ndim=1] final_out,
                 double xmin, double xmax, int m,
                 double ymin, double ymax, int n,
                 void *args, int num_cores)
    cdef f_type f
    f = <f_type>fin
    ...

在另外一段代码中:

from compmech.integrate.integratev cimport trapz2d

cdef void cfk0L(int npts, double *xs, double *ts, double *out,
                double *alphas, double *betas, void *args) nogil:
    ...

trapz2d(<void *>cfk0L, fdim, k0Lv, xa, xb, nx, ta, tb, nt, &args, num_cores)
2

这确实看起来像是一个错误,因为系统在尝试合并 filename.pxdfilename.pyx 这两个文件中的类型时失败了。使用 void* 是一种解决方法,但如果你想避免类型转换,可以创建一个第三个文件 _util.pxd,里面包含函数指针的共享定义。

# _util.pxd

ctypedef void (*f_type)(int npts, double *xs, double *ts, double *out,
                        double *alphas, double *betas, void *args) nogil

然后你可以把这个共享的类型定义导入到 integrate.pxdintegrate.pyx 中,这样就能确保这两个地方的类型是一样的。

撰写回答