【问题标题】:How do you wrap a C function that returns a pointer to a malloc'd array with ctypes?如何包装一个 C 函数,该函数返回一个指向带有 ctypes 的 malloc 数组的指针?
【发布时间】:2020-08-22 19:01:24
【问题描述】:

我有一个 C 函数,它读取二进制文件并返回一个动态大小的无符号整数数组(大小基于二进制文件中的元数据):

//example.c
#include <stdio.h>
#include <stdlib.h>

__declspec(dllexport)unsigned int *read_data(char *filename, size_t* array_size){
  FILE *f = fopen(filename, "rb");
  fread(array_size, sizeof(size_t), 1, f);
  unsigned int *array = (unsigned int *)malloc(*array_size * sizeof(unsigned int));
  fread(array, sizeof(unsigned int), *array_size, f);
  fclose(f);

  return array;
}

这个answer 似乎在说将创建的数组从 C 传递到 Python 的正确方法是这样的:

# example_wrap.py
from ctypes import *
import os

os.add_dll_directory(os.getcwd())
indexer_dll = CDLL("example.dll")

def read_data(filename):
    filename = bytes(filename, 'utf-8')
    size = c_size_t()
    ptr = indexer_dll.read_data(filename, byref(size))
    return ptr[:size]

但是,当我运行 python 包装器时,代码在ptr[:size] 处静默失败,就好像我试图越界访问数组一样,我可能是,但是传递这个动态大小的正确方法是什么数组?

【问题讨论】:

  • 您在 python 代码中调用的indexer_dll.read_index() 的定义在哪里?
  • 在贴出的 C 代码中。哦,抱歉,我正在重命名并减少我的代码以使其更通用,但我错过了更改该名称。

标签: python c ctypes


【解决方案1】:

一些注意事项:

首先,您需要正确设置C函数的原型,以便ctypes可以正确地在C和Python类型之间进行转换。

其次,由于size实际上是一个ctypes.c_size_t对象,所以实际上需要使用size.value来访问数组大小的数值。

第三,由于 ptr[:size.value] 实际上将数组内容复制到 Python 列表中,因此您需要确保 free() 也分配了 C 数组,因为您将不再使用它。

(也许在这里将数组复制到 Python 列表并不理想,但我假设在这里没问题,否则在 Python 中处理 C 数组时会更加复杂。)

这应该可行:

from ctypes import *
import os

os.add_dll_directory(os.getcwd())
indexer_dll = CDLL("example.dll")
indexer_dll.read_data.argtypes = [c_char_p, POINTER(c_size_t)
indexer_dll.read_data.restype = POINTER(c_int)
libc = cdll.msvcrt

def read_data(filename):
    filename = bytes(filename, 'utf-8')
    size = c_size_t()
    ptr = indexer_dll.read_data(filename, byref(size))
    result = ptr[:size.value]
    libc.free(ptr)
    return result

【讨论】:

  • 你解决了我问的问题,谢谢。它在 libc.free(ptr) 处静默失败。
  • 可能 msvcrt 正在使用不同的库。我通过创建一个 free_mem C 函数并通过 dll 调用它来修复它。
  • @CSStudent7782 是的,我在 Linux 上测试过它(你实际加载 libc.so),在 Windows 上它可能完全不同......导出你自己的函数肯定会工作!
猜你喜欢
  • 1970-01-01
  • 2020-01-12
  • 2012-05-06
  • 1970-01-01
  • 2011-01-12
  • 1970-01-01
  • 1970-01-01
  • 2021-07-02
  • 2021-06-25
相关资源
最近更新 更多