Я связываю фортранскую библиотеку с python, используя c_types. Я инициализирую структуры в python, передаю их фортрану, который заполняет их, и читаю их обратно в python. Все отлично работает с массивом чисел, но теперь я застрял с сопряженными строковыми массивами.
Я пробовал подобный пример one , и это было нормально, но в этом случае массив c_char не в структуре. Поэтому я попытался изменить предыдущий пример, поместив массив c_char в структуру. Вот код, который я использовал, со структурой и без нее:
Python код:
from ctypes import *
lib = CDLL("./libf.so")
if 1:
print(">>> Without structure")
func = getattr(lib, "fortran2py_")
nstring = pointer(c_long(2))
carr = (c_char * 255)()
func.argtypes = [POINTER(c_long), POINTER(c_char)]
print(type(carr))
print('before:',carr)
func(nstring, carr)
str1, str2 = ''.join([v.decode("utf-8") for v in carr]).rstrip("\x00").split("\x00")
print(str1, str2)
class Struct0(Structure):
_fields_ = [
("name", c_char * 255),
]
if 1:
print(">>> With structure")
func = getattr(lib, "fortran2pystr_")
nstring = pointer(c_long(2))
carr = Struct0()
func.argtypes = [POINTER(c_long), POINTER(Struct0)]
print(type(carr.name))
print('before:',carr.name)
func(nstring, byref(carr))
print('after:',carr.name)
Код Фортрана:
module c_interop
use iso_c_binding
implicit none
integer, parameter :: STRLEN = 64
type, bind(c) :: charStr
character(c_char) :: name(255)
end type charStr
contains
subroutine fortran2py(nstring, cstring_p) bind(C, name="fortran2py_")
integer(c_int), intent(in) :: nstring
character(c_char), dimension(*), intent(inout) :: cstring_p
integer :: i, j, ks, kf, n
character(len=STRLEN) :: mystr(2)
mystr(1) = "This is the first string."
mystr(2) = "Wow. Fortran + Python + Strings = Pain !"
ks = 1
do i = 1, nstring
n = len_trim(mystr(i))
kf = ks + (n - 1)
cstring_p(ks:kf) = transfer(mystr(i)(1:n), cstring_p(ks:kf))
cstring_p(kf + 1) = c_null_char
ks = ks + n + 1
enddo
end subroutine fortran2py
subroutine fortran2pystr(nstring, cstring_p) bind(C, name="fortran2pystr_")
integer(c_int), intent(in) :: nstring
type(charStr), intent(inout) :: cstring_p
integer :: i, j, ks, kf, n
character(len=STRLEN) :: mystr(2)
mystr(1) = "This is the first string."
mystr(2) = "Wow. Fortran + Python + Strings = Pain !"
ks = 1
do i = 1, nstring
n = len_trim(mystr(i))
kf = ks + (n - 1)
cstring_p%name(ks:kf) = transfer(mystr(i)(1:n), cstring_p%name(ks:kf))
cstring_p%name(kf + 1) = c_null_char
ks = ks + n + 1
enddo
end subroutine fortran2pystr
end module c_interop
Я не получаю ошибка, за исключением того, что в модифицированной части Fortran должен заполнить массив циклов c_char carr.name для элементов mystr, но полученная строка содержит только первый элемент. Если carr не структура, а непосредственно массив c_char, python может читать все содержимое mystr.
Вывод:
>>> Without structure
<class '__main__.c_char_Array_255'>
before: <__main__.c_char_Array_255 object at 0x151b3b092bf8>
This is the first string. Wow. Fortran + Python + Strings = Pain !
>>> With structure
<class 'bytes'>
before: b''
after: b'This is the first string.'
Как вы можете видеть тип carr и carr .name тоже не одно и то же. Ты хоть представляешь, что не так с моим измененным кодом? Спасибо!