在 python 中使用 ctypes 我可以使用指向其第一个元素的指针将数组自由地传递给 C 函数,因为数组衰减为指向其第一个元素的指针C。所以对于 C 函数签名
void insert_sort(int A[], size_t length);
我可以实现以下 python 包装器。
import ctypes
from typing import List, Callable
def wrap_function(lib: ctypes.CDLL, name: str, restype: object, argtypes: List[object]) -> Callable:
"""Simplify wrapping ctypes functions"""
func = lib.__getattr__(name)
func.restype = restype
func.argtypes = argtypes
return func
lib = ctypes.CDLL("path/to/library.so")
insert_sort = wrap_function(lib, 'insert_sort', None, [ctypes.POINTER(ctypes.c_int), ctypes.c_size_t])
但是 C 还允许一个人拥有数组的数组以及更多可变大小的数组数组。例如,下面的 C 函数签名演示了这一点。
void matrix_multiply(size_t n, int A[n][n], int B[n][n], int C[n][n]);
如何包装这个函数?为了整理我的问题,下面的空白处是什么?
matrix_multiply = wrap_function(lib, 'matrix_multiply', None, [...What goes here...])
如果知道数组的大小,我们可以简单地写
matrix_multiply = wrap_function(lib, 'matrix_multiply', None, [
ctypes.c_size_t, ((ctypes.c_int * 4)*4), ((ctypes.c_int * 4)*4), ((ctypes.c_int * 4)*4)
])
对于大小为 4 的数组。但是当这个数字未知时我们能做什么呢?
最佳答案
此答案基于对 ABI 的逆向工程。我把这个测试程序编译成汇编...
#include <stddef.h>
extern void matrix_multiply(size_t n, int A[n][n], int B[n][n], int C[n][n]);
extern int X[64][64];
extern int Y[64][64];
extern int Z[64][64];
void test(void)
{
matrix_multiply(64, X, Y, Z);
}
...在 x86_64-linux 上使用 GCC 9,我得到了这个汇编语言:
test:
leaq Z(%rip), %rcx
leaq Y(%rip), %rdx
leaq X(%rip), %rsi
movl $64, %edi
jmp matrix_multiply@PLT
基于此我得出结论,可变修改的数组参数作为指向其第一个元素的指针传递,因此 matrix_multiply
的适当 ctypes 声明是
c_int_p = ctypes.POINTER(ctypes.c_int)
matrix_multiply = wrap_function(lib, 'matrix_multiply', None, [
ctypes.c_size_t, c_int_p, c_int_p, c_int_p
])
采用 NumPy 数组和/或内存 View 作为练习的包装器。
https://stackoverflow.com/questions/62489384/