你如何包装一个 C 函数,该函数返回一个指向带有 ctypes 的 malloc 数组的指针?

CSS*_*782 6 c python ctypes

我有一个 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;
}
Run Code Online (Sandbox Code Playgroud)

这个答案似乎是说将创建的数组从 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]
Run Code Online (Sandbox Code Playgroud)

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

fil*_*den 2

一些注意事项:

首先,您需要正确设置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
Run Code Online (Sandbox Code Playgroud)