【问题标题】:Creating cdata of type `REAL (* vertices)[DIM]` in CFFI在 CFFI 中创建 `REAL (* vertices)[DIM]` 类型的 cdata
【发布时间】:2016-10-08 22:14:21
【问题描述】:

我正在尝试使用 CFFI 围绕一些现有的C code 构建一个 python 接口。像往常一样,为了提高性能而对 C 代码进行了修整,它充满了大量的宏和 typedef。

ATM 我正在​​复制以下结构

#define DIM     3
typedef double  REAL;
struct Object_structure {
  int numpoints;
  REAL (* vertices)[DIM];
  int * rings;
};
typedef struct Object_structure * Object;

我试图调用的函数需要Object 类型的参数。

REAL gjk_distance(
   Object obj1, REAL (* tr1)[DIM+1],
   Object obj2, REAL (* tr2)[DIM+1],
   REAL wpt1[DIM], REAL wpt2[DIM],
   struct simplex_point * simplex, int use_seed
   );

我已经编写了以下 python 类来表示这样的对象/结构,但是我无法将其转换为预期的 cdata 对象。 (现在我只考虑一个 UnitCube,但最终我想概括一下。)

class Box:
    def __init__(self, pos):
        self._weakkeydict = weakref.WeakKeyDictionary()
        self.numpoints = 8
        self.rings = [
            8, 12, 16, 20, 24, 28, 32, 36,
            3, 1, 4, -1,
            0, 2, 5, -1,
            1, 3, 6, -1,
            2, 0, 7, -1,
            7, 5, 0, -1,
            4, 6, 1, -1,
            5, 7, 2, -1,
            6, 4, 3, -1]
        x, y, z = pos
        self.vertices = [
            [x+0, y+0, z+0],
            [x+1, y+0, z+0],
            [x+1, y+1, z+0],
            [x+0, y+1, z+0],
            [x+0, y+0, z+1],
            [x+1, y+0, z+1],
            [x+1, y+1, z+1],
            [x+0, y+1, z+1],
        ]

    @property
    def cdata(self):
        self._weakkeydict.clear()

        #ptr_numpoints = ffi.new("int", self.numpoints)
        ptr_rings = ffi.new("int[]", self.rings)
        vertices = [ffi.new("REAL[3]", v) for v in self.vertices]
        ptr_vertices = ffi.new("REAL *[3]", vertices )

        ptr_obj = ffi.new("Object", { 
            'numpoints': self.numpoints,
            'rings': ptr_rings,
            'vertices': ptr_vertices})
        self._weakkeydict[ptr_obj] = (ptr_rings, ptr_vertices, vertices)
        return ptr_obj

通过以上内容,我在调用时得到IndexError: too many initializers for 'double *[3]' (got 8)ptr_vertices = ffi.new("REAL *[3]", vertices )

box1 = Box((0,0,0)) 
box2 = Box((10,0,0))
d = lib.gjk_distance( 
        [box1.cdata], ffi.NULL,
        [box2.cdata], ffi.NULL,
        ffi.NULL, ffi.NULL, 
        ffi.NULL,  0    )

在我看来,尺寸似乎以某种方式切换了。因为它应该是一个包含 3 个元素项的 8 元素数组。 我希望有人可以在这里为我指明正确的方向。

【问题讨论】:

    标签: python c cffi


    【解决方案1】:

    如果您要创建单个项目,请使用ffi.new('REAL(*)[3]', [1, 2, 3])* 周围的括号很重要。

    在 C 中,REAL(*)[3] 类型表示指向 REAL 数组 (size=3) 的指针,而REAL*[3] 表示指向 real 数组 (size=3) 的指针。详情请见C pointer to array/array of pointers disambiguation

    现在,您正在创建一个项目数组,CFFI expects an array type 而不是 as you have already discovered。可以这样比较:

    ffi.new('int*', 1)    # ok
    ffi.new('int[]', 1)   # wrong
    ffi.new('int*', [1, 2, 3])    # wrong
    ffi.new('int[]', [1, 2, 3])   # ok
    
    ffi.new('REAL(*)[3]', [0.1, 0.2, 0.3])    # ok
    ffi.new('REAL[][3]', [0.1, 0.2, 0.3])     # wrong
    ffi.new('REAL(*)[3]', [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]])    # wrong
    ffi.new('REAL[][3]', [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]])     # ok
    

    【讨论】:

    • 谢谢。你能评论一下这与REAL[][3]有什么关系吗?
    • 顺便说一句,ffi.new('REAL(*)[3]') 在这里不起作用,但 ffi.new("REAL[][3]") 可以。显然 CFFI 语法并不完全是 C 语法。应该存储的是(在这种情况下)8 x 3 二维(嵌套)数组,其中 3 是内部/第二维的大小。我的理解是,不是定义一个固定大小的 8x3 数组,而是通过指向第一个 3 元素子数组的指针来概括外部维度,因此 c 声明是 REAL(*)[3]。在 CFFI 中,由于我不明白的原因,这显然必须翻译为 REAL[][3]
    【解决方案2】:

    显然ptr_vertices = ffi.new("REAL[][3]", self.vertices ) 是要走的路。目前看来它可以工作。

    【讨论】:

      猜你喜欢
      • 2016-09-10
      • 2016-07-02
      • 1970-01-01
      • 2016-04-08
      • 1970-01-01
      • 2021-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多