【问题标题】:passing arrays with ctypes使用 ctypes 传递数组
【发布时间】:2014-12-04 07:39:10
【问题描述】:

我有一个 C 函数

void read_FIFO_AI0(int16_t** input, size_t size, NiFpga_Session* session, NiFpga_Status* status)
{
  *input = (int16_t*) malloc (size*sizeof(int16_t));
  // function that populates the array *input
}

填充数组“*input”。现在我想将该数组中的数据传递给 python 进行进一步处理。我尝试使用 ctypes 来做到这一点:

def read_FIFO_AI0(size,session,status):
    _libfpga.read_FIFO_AI0.argtypes = [POINTER(ARRAY(c_int16, size)), c_int, POINTER(c_uint32), POINTER(c_int32)]
    _libfpga.read_FIFO_AI0.restype = None

    values = (c_int16*size)()
    _libfpga.read_FIFO_AI0(byref(values),size,byref(session),byref(status))
    return values

代码执行,但我在数组中得到错误的结果。当我尝试在 C 中使用 C 函数时,我得到了正确的结果:

size_t size=20;
int16_t* input;

read_FIFO_AI0(&input, size, &session, &status);

填充数组以便我可以在 Python 中访问数据的正确方法是什么?我不依赖于使用指向填充数组的指针,我也可以在 C 函数中创建数组并将其作为返回发送给 Python,但我也没有开始工作。

【问题讨论】:

    标签: python c arrays ctypes


    【解决方案1】:

    第一个参数的类型是POINTER(POINTER(c_int16)) 而不是POINTER(ARRAY(c_int16,size))

    这是一个简短的例子:

    x.c(用cl /LD x.c编译:

    #include <stdlib.h>
    #include <stdint.h>
    __declspec(dllexport) void read(int16_t** input, size_t size)
    {
      int i;
      int16_t* p = (int16_t*) malloc (size*sizeof(int16_t));
      for(i=0;i<size;i++)
        p[i] = i;
      *input = p;
    }
    __declspec(dllexport) void release(int16_t* input)
    {
        free(input);
    }
    

    x.py

    from ctypes import *
    x = CDLL('x')
    x.read.argtypes = POINTER(POINTER(c_int16)),c_size_t
    x.read.restype = None
    x.release.argtypes = [POINTER(c_int16)]
    x.release.restype = None
    p = POINTER(c_int16)()
    x.read(p,5)
    for i in range(5):
        print(p[i])
    x.release(p)
    

    输出:

    0
    1
    2
    3
    4
    

    请注意,如果您不记得 freemalloc,这会给您带来潜在的内存泄漏。更好的方法是在 Python 中分配缓冲区并告诉 C 函数大小:

    x.c

    #include <stdlib.h>
    #include <stdint.h>
    __declspec(dllexport) void read(int16_t* input, size_t size)
    {
      int i;
      for(i=0;i<size;i++)
        input[i] = i;
    }
    

    x.py

    from ctypes import *
    x = CDLL('x')
    x.read.argtypes = POINTER(c_int16),c_size_t
    x.read.restype = None
    p = (c_int16*5)()
    x.read(p,len(p))
    print(list(p))
    

    输出

    [0, 1, 2, 3, 4]
    

    【讨论】:

    • 我实现了第二种方法,它就像一个魅力。谢谢!这是否意味着,内存分配和释放完全由 Python 处理?所以我不必担心内存泄漏或类似的事情?
    • 是的,上面的p 是对缓冲区的引用。当p 超出范围时,缓冲区的引用计数将减少,如果它是最后一个引用,它将被释放。
    猜你喜欢
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    • 2014-04-20
    • 2017-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-13
    相关资源
    最近更新 更多