在 Python 中将 C 指针转换为 numpy 数组的问题

问题描述 投票:0回答:1

我正在尝试在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数组的问题吗?

提前感谢您的帮助!

python numpy pointers fortran ctypes
1个回答
0
投票

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.]
© www.soinside.com 2019 - 2024. All rights reserved.