关于 c :ctypes: 初始化数组并传递给 C 函数

ctypes: Initialize array of arrays and pass to C function

我一直在玩 ctypes,遇到了两个问题:

问题 1. 我想使用 double* 数组构建一个 cellComplex,但我希望 new_cellComplex 接受一个 double*\\ 的数组(以及一个 size_t 参数),而不是一个固定数量的 double*\\'s。使用固定数字,代码看起来像这样(并且运行良好):

1
2
3
4
5
6
7
8
9
10
11
extern"C" {
  void * new_cellComplex(double* p_x, double* p_y, double* p_z) {

    std::vector< std::pair<double,double> > point;
    point.push_back( std::make_pair(p_x[0],p_x[1]));
    point.push_back( std::make_pair(p_x[0],p_x[1]));
    point.push_back( std::make_pair(p_x[0],p_x[1]));

    cellComplex<double>* cmplx = new cellComplex<double>(point);
    return cmplx;
  }

使用 Python 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
import ctypes

cellComplex_lib = ctypes.cdll.LoadLibrary('./cellComplex_lib.so')
cellComplex_lib.new_cellComplex.restype  = ctypes.c_void_p
cellComplex_lib.new_cellComplex.argtypes = [ctypes.c_double*2,
                                            ctypes.c_double*2,
                                            ctypes.c_double*2]

p_x = (ctypes.c_double*2)(0.0,1.0)
p_y = (ctypes.c_double*2)(0.0,1.0)
p_z = (ctypes.c_double*2)(0.0,1.0)

cmplx = cellComplex_lib.new_cellComplex(p_x,p_y,p_z)

我宁愿有以下(段错误):

1
2
3
4
5
6
7
8
9
10
11
extern"C" {
  void * new_cellComplex(double** p, size_t dim) {

    std::vector< std::pair<double,double> > point;
    for (size_t i=0; i<dim; ++i) {
      point.push_back( std::make_pair(p[i][0],p[i][1]));
    }
    cellComplex<double>* cmplx = new cellComplex<double>(point);
    return cmplx;
  }
}

使用 Python 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import ctypes

dim = 3
cellComplex_lib = ctypes.cdll.LoadLibrary('./cellComplex_lib.so')
cellComplex_lib.new_cellComplex.restype  = ctypes.c_void_p
cellComplex_lib.new_cellComplex.argtypes = [(ctypes.c_double*2)*dim,
                                            ctypes.c_size_t]

p_x = (ctypes.c_double*2)(0.0,1.0)
p_y = (ctypes.c_double*2)(0.0,1.0)
p_z = (ctypes.c_double*2)(0.0,1.0)

p = ((ctypes.c_double*2)*dim)(p_x,p_y,p_z)

cmplx = cellComplex_lib.new_cellComplex(p,dim)

^这不起作用,我不知道为什么。

问题 2。(包括在此处是因为它在问题 1 中很明显)我正在从我的 C 代码返回一个本质上匿名的指针!这只是感觉,嗯,很脏,并且必须有更好的方法来返回自定义数据类型并在 Python 中处理它。作为记录,我非常感谢这个 stackoverflow 的答案,我在其中学到了这样的巫术 - 但只要它在我的代码中,我就无法在晚上睡觉......


使用 double [][2] 代替 double **。您正在传递一个连续的 C 数组,您希望将其作为指向一行 2 项的指针进行访问。第一个索引是行索引。

将数组声明为 double ** 是指向 double 指针的指针,因此 p[i] 是指针,而 p[i][0] 再次取消引用它。但是根据您的数据, p[i] 是一个 NULL 指针。

Refer to the comp.lang.c FAQ, question
6.18: My compiler complained when I passed a two-dimensional array to a function expecting a
pointer to a pointer.

对于返回类型,您可以继承 c_void_p,或者使用 ctypes 文档中第 15.17.1.7 节最后一段的钩子 from_param_as_parameter_