我正在尝试在Python中使用ctypes来利用C库。 C 库提供了一个子例程,它通过指针返回两个数组:一个用于整数数据,一个用于浮点数据。
这是我的 Python 代码的简化示例:
import ctypes
import numpy as np
lib = ctypes.CDLL('./reader.so') # Assicurati di sostituire con il percorso corretto della tua libreria
readdata = lib.readdata
readdata.argtypes = [ctypes.POINTER(ctypes.POINTER(ctypes.c_int)), ctypes.POINTER(ctypes.POINTER(ctypes.c_float))]
data_ptr = ctypes.POINTER(ctypes.c_int)()
xyz_ptr = ctypes.POINTER(ctypes.c_float)()
readdata(ctypes.byref(data_ptr), ctypes.byref(xyz_ptr))
size = 17 # Dimensione dell'array
data = np.frombuffer((ctypes.c_int * size).from_address(ctypes.addressof(data_ptr.contents)), dtype=np.int32)
xyz = np.frombuffer((ctypes.c_float * size).from_address(ctypes.addressof(xyz_ptr.contents)), dtype=np.float32)
print("Dati integer:", data)
print("Dati float:", xyz)
libc = ctypes.CDLL(None)
libc.free(data_ptr)
这是fortran模块(reader.so)的代码:
subroutine readdata(data1, data2) bind(c, name='readdata')
use iso_c_binding
implicit none
integer(c_int), intent(out), dimension(:), allocatable :: data1
real(c_float), intent(out), dimension(:), allocatable :: data2
integer :: length, i
length = 17 ! Esempio di dimensione, sostituire con la dimensione effettiva
allocate(data1(length))
allocate(data2(length))
! Assegna dati casuali all'array di interi data1
do i = 1, length
data1(i) = i * 10 ! Modifica questo assegnamento con la logica desiderata
end do
! Assegna dati casuali all'array di float data2
do i = 1, length
data2(i) = real(i * 10, kind=4)
end do
end subroutine readdata
问题是我在尝试将指针转换为 numpy 数组时遇到错误。我怀疑指针可能彼此靠近,并可能导致内存重叠问题。
我尝试过重新安排操作并手动释放内存,但无法解决问题。
有人可以帮我理解如何正确解决在Python中将C指针转换为numpy数组的问题吗?
提前感谢您的帮助!
Fortran 可分配数组不是指向引用的指针。这是一个更为复杂的结构,请参见第 17 页。 18.5.3 “CFI_cdesc_t 结构类型”(ISO/IEC 1539-1:2018)和/或头文件“ISO_Fortran_binding.h”。
Numpy (Python) 分配数组是最简单的方法:
import ctypes
import numpy as np
lib = ctypes.CDLL('./readdata2.so') # Assicurati di sostituire con il percorso corretto della tua libreria
readdata2 = lib.readdata2
length = 17
data = np.empty(length, dtype=np.int32)
xyz = np.empty(length, dtype=np.float32)
data_ptr = data.ctypes.data_as(ctypes.POINTER(ctypes.c_int))
xyz_ptr = xyz.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
readdata2(data_ptr, xyz_ptr, ctypes.c_int(length))
print("Dati integer:", data)
print("Dati float:", xyz)
subroutine readdata2(data1, data2, length) bind(c, name='readdata2')
use iso_c_binding
implicit none
integer(c_int), intent(in), value :: length
integer(c_int), intent(inout) :: data1(length)
real(c_float), intent(inout) :: data2(length)
integer :: i
! Assegna dati casuali all'array di interi data1
do i = 1, length
data1(i) = i * 10 ! Modifica questo assegnamento con la logica desiderata
end do
! Assegna dati casuali all'array di float data2
do i = 1, length
data2(i) = real(i * 10, kind=4)
end do
end subroutine readdata2
$ gfortran -shared readdata2-240509.f90 -o readdata2.so && python readdata2-240509.py
Dati integer: [ 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170]
Dati float: [ 10. 20. 30. 40. 50. 60. 70. 80. 90. 100. 110. 120. 130. 140.
150. 160. 170.]